集成 MPWeex 到 Android

在执行以下步骤之前,请先确认您的Android开发环境是ok的。

1. 增加软件仓库

根目录下的build.gradle文件下加入软件仓库

allprojects {
    repositories {
        google()
        jcenter()
        
        maven {
            url 'http://dev.txmpay.com:18081/repository/maven-public/'
            name 'nexus'
            credentials {
                username = ""
                password = ""
            }
        }
    }
}

2. 设置gradle依赖

目前暂不支持androidx

dependencies {
    ...
    // 修改为app版本,建议为28+
    implementation "com.android.support:recyclerview-v7:28.0.0"
    implementation "com.android.support:support-v4:28.0.0"
    implementation "com.android.support:appcompat-v7:28.0.0"
    implementation "com.android.support:gridlayout-v7:28.0.0"
    implementation "com.android.support:design:28.0.0"

    // mpweex sdk 必须的依赖
    implementation "com.lmspay.mpweex:mpweex_sdk:0.28.2.3"
    implementation "com.lmspay.unionpay:unionpay:0.1.1"
    implementation "com.aliyun.dpa:oss-android-sdk:2.9.2"
    implementation "com.alibaba:fastjson:1.2.68"
    implementation "com.contrarywind:Android-PickerView:4.1.6"

    //glide 修改为app的图片加载库
    implementation 'com.github.bumptech.glide:glide:3.7.0'
    implementation 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
    implementation 'com.squareup.okhttp3:okhttp:3.11.0'
    
    //定位功能 可选
    implementation 'com.amap.api:location:4.7.2'
}

3. 解决NDK C++库冲突

如果工程内有引用c++_shared库,则可以在工程内添加以下配置,解决冲突,因为SDK内已经有相应的库文件了。

android {
    // 过滤多余的动态库
    packagingOptions {
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
        pickFirst 'lib/x86/libc++_shared.so'
    }
}

4. 配置debug参数

WARNING

debug 中用到的txm_test.jks及mpweex.bmp仅用于APP集成初期使用 APP在小程序平台入网后,需要使用APP打包发布时的JKS及新生成的mpweex.bmp

4.1 配置Debug的应用签名

4.1.1 修改gradle.properties

DEBUG_KEY_ALIAS =android
DEBUG_KEY_PASSWORD =android
DEBUG_STORE_FILE =txm_test.jks
DEBUG_STORE_PASSWORD =android

4.1.2 修改build.gradle

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"

    signingConfigs {
        debug {
            keyAlias DEBUG_KEY_ALIAS
            keyPassword DEBUG_KEY_PASSWORD
            storeFile file(DEBUG_STORE_FILE)
            storePassword DEBUG_STORE_PASSWORD
        }
    }

4.1.3 txm_test.jks

可将Demo工程app目录内的txm_test.jks放置在工程app目录下。如果放至其它目录,则需要修改gradle.properties配置中的DEBUG_STORE_FILE路径

4.2 配置Debug的白盒密码

可将Demo工程app/src/main/assets目录下的mpweex.bmp文件拷贝到工程对应目录下。release时,需要替换成正式的mpweex.bmp,APP入网后会提供。

5. 配置混淆规则

混淆规则如下

# weex
-keep class org.apache.weex.bridge.**{*;}
-keep class org.apache.weex.dom.**{*;}
-keep class org.apache.weex.layout.**{*;}
-keep class org.apache.weex.base.**{*;}
-keep class org.apache.weex.common.**{*;}
-keep class * implements org.apache.weex.IWXObject{*;}
-keep class org.apache.weex.ui.**{*;}
-keep class org.apache.weex.ui.component.**{*;}
-keep class org.apache.weex.utils.**{
    public <fields>;
    public <methods>;
    }
-keepclassmembers class * {
    @org.apache.weex.annotation.JSMethod *;
}

-keep class org.apache.weex.base.SystemMessageHandler { *; }
-dontwarn org.apache.weex.bridge.**

# mpweex
-keep class com.lmspay.zq.widget.indicators.**{*;}
-keep class com.lmspay.zq.model.**{*;}

# fastjosn
-keep class com.alibaba.fastjson.** {
 *;
}
-dontwarn com.alibaba.fastjson.**

## --- yicrypto ---
-keep class net.yiim.yicrypto.** {
    public *;
    native <methods>;
}

# 不混淆银联
-keep class com.unionpay.** {*;}
-keep interface com.unionpay.** {*;}
-keep class cn.gov.pbc.tsm.** {*;}
-keep interface cn.gov.pbc.tsm.** {*;}
-keep class org.simalliance.openmobileapi.** {*;}
-dontwarn com.unionpay.**
-dontwarn cn.gov.pbc.tsm.**

5.1 使用Glide图片库

如果项目中使用Glide图片库,则需要增加以下混淆参数

#---glide---
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

#---Matisse---
-dontwarn com.bumptech.glide.**

6. 声明权限

AndroidManifest.xml中声明权限

<!-- 振动 -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 请求网络 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 读取缓存数据 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 调起系统电话 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--摄像头-->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<!--定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

7. 初始化sdk

APP商户入驻成功后,系统会分配APPID和白盒密码算法密钥mpweex.bmp 将mpweex.bmp放置项目的asserts目录

MPWeexSDK.getInstance().setBasePath("mpweex api host");
MPWeexSDK.getInstance().setAppId("your mpweex appid.");


// 初始化mpweex
InitConfig initConfig = new InitConfig.Builder()
        .build();
MPWeexSDK.getInstance().initialize(this, initConfig, BuildConfig.DEBUG);

WARNING

初始化顺序,setAppId必须在initialize前面,否则容易引起偶发性闪退

8. 扩展图片加载

推荐使用Glide框架实现图片加载。如果自定义图片加载,则需要实现IWXImgLoaderAdapter

参见:GlideImageAdapter

9. 扩展定位(可选)

推荐使高德定位,如果自定义定位加载,则需要实现IWXGeoAdapter

参见:AmapGeoAdapter

10. 登录信息同步

APP内,如果要完全支持小程序功能,用户需要在小程序平台进行登录信息同步。在APP启动并且用户已登录,调用此接口。

TIP

此接口是幂等的,可重复调用,平台内只会进行一次用户信息登记。后续调用平台将会进行用户资料的同步操作。

注意调用时机

此接口需要在每次APP启动时,就去检查并调用,因为集成完SDK后,老版本APP已登录的用户,也需要将用户信息同步至小程序平台。 故需要APP启动后,判断APP用户是否已登录,已登录则调用用户信息同步即可。

接口描述

/**
 * 登录成功后,将用户信息同步至小程序平台
 * 则操作为异步操作,如果需要监听SDK是否已经完成,可以通过callback监听
 *
 * @param platformuid APP商户应用的用户ID
 * @param phoneno 手机号码
 * @param callback 异步回调,如果需要等待SDK完成,则可通过回调监听
 */
public void syncAccount(String platformuid,
                    String phoneno,
                    final MPWeexSDK.ResponseCallback callback);

DEMO

MPWeexSDK.getInstance().syncAccount("your app user identity", 
    "your app user phone number",
    new MPWeexSDK.ResponseCallback() {
        @Override
        public void onResponse(final boolean ok, int statusCode, 
            final Object data, Map<String, String> headers) {
            // your code if needed.
        }
    });

11. 退出登录通知接口

APP内,如果退出登录了,需要调用此接口通知SDK,以进行登录状态的同步。

/**
 * 退出登录时,通知SDK
 */
public void onLogout();

DEMO

// 通知SDK退出登录
MPWeexSDK.getInstance().onLogout();

12. 判断APP用户是否登录

因为大部分小程序都是需要用户登录后,才可以访问的,故需要APP实现IWXUserInfoAdapter告之小程序SDK,用户是否已登录成功。

TIP

主要实现ensureLogged,getUserInfo忽略

此适配器主要用于APP定制登录跳转或友好提示。

接口示例:

public class UserInfoAdpater implements IWXUserInfoAdapter {
    @Override
    public WXUserInfoModel getUserInfo(Activity activity) {
        // deprecated, ignore it.
        return null;
    }

    /**
     * 用于判断APP用户是否已登录,请将方法内逻辑替换为APP判断用户是否已登录的逻辑。
     * @param activity 上下文
     * @return true if logged.
     */
    @Override
    public boolean ensureLogged(Activity activity) {
        // 用户已登录则返回true

        // 如果未登录,则跳转至登录界面,返回false
//        if( ! logged ) {
//            // 跳转至登录页或弹toast进行提示
//            Intent intent = new Intent(activity, LoginActivity.class);
//            activity.startActivity(intent);
//            return false;
//        }

        return true;
    }
}

12.1 修改初始化参数

// 初始化mpweex
InitConfig initConfig = new InitConfig.Builder()
        .setImgAdapter(new GlideImageAdapter())
        .setGeoAdapter(new AmapGeoAdapter())
        .setUserInfoAdapter(new UserInfoAdpater())
        .build();
MPWeexSDK.getInstance().initialize(this, initConfig, BuildConfig.DEBUG);

13. SDK其它API使用方法

13.1 跳转至指定小程序

在APP中,可通过MPID跳转到指定的小程序。

  • 接口
/**
 * 跳转至小程序
 * @param context Context上下文
 * @param mpid 小程序ID
 * @param logo 小程序图标
 * @param systemType 小程序系统类型 0 宿主 1普通 2游戏
 * @param canOffline 是否支持离线访问 0不支持 1支持,不支持离线访问的,需要先登录
 * @param mpdesc 小程序描述
 */
public void jumpToMP(Activity context, String mpid, String logo, int systemType,
                     int canOffline, String mpdesc);
  • 调用示例
MPWeexSDK.getInstance().jumpToMP(
    MainActivity.this, 
    "MPAAABa7vz87hIvbIAq1lG", // MPID
    "images/AAFLlQAAAWzlpHpnAgI", // MPID LOGO
    1, // MPID TYPE,默认1
    0, // 是否支持离线访问
    ""
);

13.2 跳转至指定页面

在APP中,可通过SDK跳转到指定的小程序页面。

  • 接口
/**
 * 跳转到指定页面
 * @param activity 上下文
 * @param page 指定页面
 */
public void jumpToPage(Activity activity, MPPage page);
  • 页面参数
enum MPPage {
    PAGE_INDEX, // 小程序主页
    PAGE_RECENT, // 最近使用
    PAGE_MYMP, // 我的小程序
    PAGE_RECOMMEND, // 推荐的
    PAGE_SEARCH; // 搜索
}
  • 调用示例
MPWeexSDK.getInstance().jumpToPage(this,
    MPWeexSDK.MPPage.PAGE_INDEX);