GMU小程序SDK集成(Android)
一、概述
GMU小程序SDK为使用者提供了一套完整的小程序方案,它包含GMU小程序页面渲染、页面堆栈管理、小程序版本发布、用户反馈的功能。
二、集成前准备
1、平台配置
- 小程序SDK与服务端通信时的鉴权流程依赖GMU小程序开放平台提供的“应用KEY”和“应用SECRET”,因此SDK初始化时需要提供“应用KEY”和“应用SECRET”。 
- 除了“应用KEY”和“应用SECRET”,android还需额外配置apk签名串,如图所示: 

获取方式如下:
使用 keytool(需安装java jdk)找到keystore文件,获取SHA1值
1)Ctrl+R快捷键,调出窗口,输入cmd进入控制台。
2)控制台进入到jdk下的bin目录,例:cd C:\Program Files\Java\jdk1.8.0_131\bin回车键;
再输入keytool -list -keystore keystore文件的路径,例:keytool -list -keystore C:\Users\Administrator\Desktop\xxx.keystore,回车键执行读取签名文件
提示输入密钥库口令,输入密钥后回车(如果没设置密码,可直接回车)此时可在控制台显示的信息中获取SHA1值,例如:39:CC:E7:7D:01:6C:0A:1A:CA:3D:13:20:D7:2D:C0:50:4B:38:4C:21,将SHA1值的冒号去除,大写字母改为小写后填入平台,例如:39cce77d016c0a1aca3d1320d72dc0504b384c21
2、集成清单
SDK库文件
- miniappsdk.aar,登录您的GMU小程序开放平台账号,从左侧SDK集成页面上下载。 
系统库依赖
- SDK 28
- build tool 28.0.3
- support-v4:28.0.0
- appcompat-v7:28.0.0
- preference-v7:28.0.0
三方库依赖
- Gson
- OKHttp 3
- Glide 4.9
- J2V8
三、集成说明
1、编译必要配置
build.gradle配置
1.配置框架必要项
2.指定库路径,这里举例将库路径指定为工程根路径的libs文件夹下(这个路径开发者自行分配这里只是举例,gradle依赖列表中的所所有配置以此为根据编写)
3.依赖库android{
    ...
    defaultConfig {
        resValue "string", "lightAppid",""
        applicationId "apk包名"
        android.defaultConfig.manifestPlaceholders.label = "应用名称,这个文案将影响到已运行的小程序在最近列表页中显示的标题"
        ndk {
            abiFilters "armeabi-v7a","armeabi"
        }
    }
    repositories {
        flatDir {
            dirs '../libs'
        }
    }
    ...
}
dependencies {
    implementation 'com.android.support:support-v4:28.0.0'
	implementation 'com.android.support:appcompat-v7:28.0.0'
	implementation 'com.android.support:preference-v7:28.0.0'
	implementation 'com.squareup.okio:okio:1.15.0'
	implementation 'com.squareup.okhttp3:okhttp:3.12.0'
	implementation 'commons-net:commons-net:3.3'
	implementation 'com.google.code.gson:gson:2.8.0'
	//框架图片库依赖,glide 4.9
	implementation('com.github.bumptech.glide:glide:4.9.0', {
		exclude group: "com.android.support"
	})
    //框架小程序依赖
	implementation(name:'j2v8-6.0.0',ext:'aar',group:'com.eclipsesource.j2v8',version:'1.0')
    implementation(name:'miniappsdk-0.1',ext:'aar')
}
2、运行必要配置
AndroidManifest.xml配置
为适配Android11存储方面的修改,框架需要使用FileProvider加载文件。如果您的工程里已经包含了包名.provider这样的配置,则只需要在android:resource中指定的路径配置文件里添加我们框架需要的配置即可。<provider
     android:name="android.support.v4.content.FileProvider"
     android:authorities="${applicationId}.provider"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
         android:name="android.support.FILE_PROVIDER_PATHS"
         android:resource="@xml/provider_paths"/>
 </provider>
关联到资源文件res/xml/provider_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <paths>
        <external-path
            name="download"
            path="."/>
        <external-path
            name="external_storage_root"
            path="." />
        <files-path
            name="files-path"
            path="." />
        <cache-path
            name="cache-path"
            path="." />
        <!--/storage/emulated/0/Android/data/...-->
        <external-files-path
            name="external_file_path"
            path="." />
        <!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录-->
        <external-cache-path
            name="external_cache_path"
            path="." />
        <!--配置root-path。读取到sd卡和一些应用分身的目录,否则可能会导致 java.lang.IllegalArgumentException: Failed to find configured root that ...-->
        <root-path
            name="root-path"
            path="" />
    </paths>
</paths>
该资源文件放置在下图所示的路径:

四、权限声明
框架所有必要权限都已经在包内声明,外部不用再在AndroidManifest.xml文件中声明。框架提供了现式的获取危险权限的的API PermissionsHelper,用法在框架启动示例代码中已经展示。
五、API设计
1、框架初始化
GMUMiniApi init 必须定义在Applicaiton中,否则小程序无法正常运行
| 入参类型及范围 | 说明 |
| :—-| :—- |
|Context|不可为空|public class MyApplication extends Application {
    
    public void onCreate() {
        super.onCreate();
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            String processName = getProcessName();
            //判断不等于默认进程名称,AndroidP上子进程若要访问网络必须做此操作
            if (!getPackageName().equals(processName)){
                WebView.setDataDirectorySuffix(processName);
            }
        }
        //必:初始化GMU框架
        GMUMiniApi.getInstance().init(this);
    }
}
2、框架启动
GMUMiniApi startWithConfig 框架启动方法
| 入参类型及范围 | 说明 |
| :—-| :—- |
|config|必传。SDK初始化配置对象,配置对象需要提供必需的appKey和appSecret。如果SDK需要连接1.0私有云平台,可为配置对象提供server属性来指定私有云服务器;|
|GMUMiniApi.StartStatus|可为空。若预置了小程序的资源包数量比较多的话,初始化会比较耗时,若不监听则会在后台做资源准备工作,需要确保在用户打开小程序前是执行完毕的|//想要框架所有功能能够正常使用,建议在初始化时请求READ_PHONE_STATE、WRITE_EXTERNAL_STORAGE这两个必要权限。
String[] permissions = {Manifest.permission.READ_PHONE_STATE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
PermissionsHelper.checkPermission(this,permissions, new PermissionCallBack() {
    
    public void onSucessed(Bundle bundle) {
		GMUMiniConfig config = new GMUMiniConfig();
		config.server = "https://mpapi.lightyy.com";
		config.appKey = "b489e314f4e247339d41cbb34ea0000";
		config.appSecret = "b71b317768274cf7ae22b90478200000";
        //这里是真正启动框架的代码
        GMUMiniApi.getInstance().startWithConfig(config,new GMUMiniApi.StartStatus() {
            
            public void onStart(boolean b) {
                //b为true表示启动成功,false表示失败
            }
        });
    }
    
    public void onFailed(Bundle bundle) {
        
    }
});
GMUMiniApi start(已废弃) 框架启动方法
| 入参类型及范围 | 说明 |
| :—-| :—- |
|GMUMiniApi.StartStatus|可为空。若预置了小程序的资源包数量比较多的话,初始化会比较耗时,若不监听则会在后台做资源准备工作,需要确保在用户打开小程序前是执行完毕的|//想要框架所有功能能够正常使用,建议在初始化时请求READ_PHONE_STATE、WRITE_EXTERNAL_STORAGE这两个必要权限。
String[] permissions = {Manifest.permission.READ_PHONE_STATE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
PermissionsHelper.checkPermission(this,permissions, new PermissionCallBack() {
    
    public void onSucessed(Bundle bundle) {
        //这里是真正启动框架的代码
        GMUMiniApi.getInstance().start(new GMUMiniApi.StartStatus() {
            
            public void onStart(boolean b) {
                //b为true表示启动成功,false表示失败
            }
        });
    }
    
    public void onFailed(Bundle bundle) {
        
    }
});
3、打开小程序
GMUMiniApi openMiniApp 打开平台上发布的小程序
| 入参类型及范围 | 说明 |
| :—-| :—- |
|Context|不可为空|
|String|平台上发布的小程序的id|GMUMiniApi.getInstance().openMiniApp(context,"GMUMINIAPPSDK");
六、混淆配置
框架提供的公共类和接口都不应该被混淆,若您的APK需要混淆请加上这些配置:--dontoptimize
-dontusemixedcaseclassnames
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keepattributes Signature
-keepattributes *Annotation*
-dontskipnonpubliclibraryclassmembers #保留所有public类和方法
#常规避免混淆方法,避免混淆自定义的页面,服务,广播,自定义的页面组件,枚举,序列化包
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
  public *;
}
-keep public class * {
    public *;
}
-keep public class com.hundsun.miniapp.LMAFragment{
    protected *;
}
-keep public interface com.hundsun.miniapp.debug.IDebugManager{
    *;
}
-keep public interface com.hundsun.miniapp.ILMAJSBridge{
    *;
}
-keep public class com.hundsun.miniapp.LMAInfo{
    public *;
}
-keep public class com.hundsun.miniapp.LMAInfo$*{
    <fields>;
    <methods>;
}
-keepclassmembernames class com.hundsun.miniapp.LMAInfo{*;}
-keepclassmembernames class com.hundsun.miniapp.LMAContext{*;}
-keep public class com.hundsun.miniapp.LMAJSObject{
    public *;
    protected *;
    *** onNativeCalled(...);
    *** onNativeDisposed(...);
}
-keep public class com.hundsun.miniapp.LMAJSCoreBridge{
    *** createAsyncExecutor(...);
    *** executeScript(...);
    *** disposeAsyncExecutor(...);
    *** getGlobalObjectRef(...);
    *** getObjectPropertyRef(...);
    *** addObjectProperty(...);
    *** addObjectFunction(...);
    *** protectObjectRef(...);
    *** unprotectObjectRef(...);
    *** deletePurgedContextObjectRef(...);
    *** callObjectRefFunction(...);
    *** tickTimer(...);
}
#不混淆三方库
-keep class com.eclipsesource.** {*;}