一、App离线SDK下载

首先配置开发环境 Android Studio【Electric Eel | 2022.1.1 Patch 1】、App离线SDK HBuilderX【3.8.4.20230531】、HBuilderX【3.8.4.20230531】。

申请AppKey,登录开发者中心(DCloud)后,在应用管理 - 点击应用 - 各平台信息 创建以及查看离线 AppKey,使用该应用的创建人账号才能查看。

SDK目录说明
  |-- HBuilder-Hello           App离线打包演示应用
  |-- HBuilder-Integrate-AS    集成uni-app的最简示例
  |-- SDK                      SDK库文件目录 
  |-- Feature-Android.xls      Android平台各扩展Feature API对应的详细配置
  |-- Readme.txt               版本说明文件及注意事项
  |-- UniPlugin-Hello-AS       uni原生插件开发示例

二、创建新项目

新建项目 —— 选择Empty Activity —— 输入项目名称、包名、项目本地路径、开发语言、最低版本SDK —— Finish。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app

** 注意 **:这里的MiniSDK的版本需要与uniapp项目中的manifest.json中所配置的版本相一致;UTS开发uniapp插件,那么Language请选择Kotlin。

项目创建成功将会打开Android Studio IDE窗口,这个时候Android Studio 会自动刷新项目以及Gradle build,停掉它。先不让它build,我们还没有配置Gradle、SDK、JDK版本。

1、配置SDK

点击File — settings...,打开配置页搜索SDK。      

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_02

首先,配置 Android SDK 路径点击 Edit,配置路径后下一步直至完成即可。      

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_Android_03

其次,安装需要的SDK Platforms、SDK Tools,勾选安装即可(建议使用31.0.0)。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_04

2、配置JDK

点击File — settings...,打开配置页搜索Gradle,这里也可以更换Gradle地址(我使用默认地址),选择JDK版本为1.8(uni-app原生插件要求JAVA环境为JDK1.8)。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_05

3、配置Gradle

点击File — Project Structure,打开项目配置,配置如图所示。这里避免 离线打包 或者 制作插件 可能会出现其他原因,故不使用最新的。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_06

Comile Sdk Version选择31,JDK选择1.8,其他项先不动,点击OK后等待安装即可。加入Gradle Build失败,那么请打开settings.gradle(旧版的请在Build.gradle中配置)文件配置其它maven镜像,这里就不做展示了。  

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_07

4、启动项目

到这里我们项目配置基本完成,先创建一个模拟设备启动试一试。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_08

随便选择一个设备尺寸,下一步。我们刚才配置的SDK选择的是31.0.0,那么我们这里也选择 API Level 31完成,Run App跑起来。 

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_09

三、配置App离线SDK

 1、基础库配置

将App离线SDK目录 \HBuilder-Integrate-AS\simpleDemo\libs下的依赖包都拷贝到项目\app\libs目录下,如图:

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uniapp打包的ios应用打开白屏_10

创建项目时默认的依赖可以直接删除,配置上AndroidX版本所需资源 。

dependencies {
    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation 'com.facebook.fresco:fresco:2.5.0'    
    implementation "com.facebook.fresco:animated-gif:2.5.0"
    implementation 'com.github.bumptech.glide:glide:4.9.0'
    implementation 'com.alibaba:fastjson:1.2.83'
    implementation 'androidx.webkit:webkit:1.3.0'
}

uni-app配置时需要在build.gradle中添加aaptOptions配置

android {
    aaptOptions {  
        additionalParameters '--auto-add-overlay'  
        ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"  
    }
}

** 异常 **:targetSdk 如果提示异常,请在其代码上方写入// noinspection ExpiredTargetSdkVersion

2、应用配置

 1)删除空项目的默认文件

新建的项目默认会有一个MainActivity的节点,如果需要重写application,必须继承自DCloudApplication,否则会导致SDK中业务逻辑无法正常运行。不需要重写那就删除掉即可。删除themes.xml,删除activity_main.xml。

2)配置应用启动页

将下述activity信息添加到Androidmanifest.xml的application节点中,这里就使用图片展示,如果需要可以将SDK中示例Demo中复制出来,manifest中请把自己的包名配置上”com.uni.aa”。

<activity
    android:name="io.dcloud.PandoraEntry"
    android:configChanges="orientation|keyboardHidden|keyboard|navigation"
    android:exported="true"
    android:hardwareAccelerated="true"
    android:launchMode="singleTask"
    android:screenOrientation="user"
    android:theme="@style/TranslucentTheme"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <action android:name="android.intent.action.VIEW" />
        <data android:scheme=" " />
    </intent-filter>
</activity>
<activity android:name="io.dcloud.PandoraEntryActivity"
android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc|fontScale|keyboard|smallestScreenSize|screenLayout|screenSize|uiMode"
    android:exported="true"
    android:hardwareAccelerated="true"
    android:launchMode="singleTask"
    android:permission="com.miui.securitycenter.permission.AppPermissionsEditor"
    android:screenOrientation="user"
    android:theme="@style/DCloudTheme"
    android:windowSoftInputMode="adjustResize" />

 

3)执行Rebuild Project编译项目 

编译时出现Execution failed for task ':app:checkDebugDuplicateClasses'.错误,请在gradle.properties中配置android.enableJetifier=true和android.useAndroidX=true,将会解决问题,如果还有部分类出现DuplicateClasses请配置忽略,这里就不再描述了。

这个时候,应用都能够正常运行了,出现一个loading页面,那么我们将开始配置资源。

3、资源配置

1)创建data文件夹并拷贝资源

Android studio默认项目没有assets文件夹,将下载的SDK->assets文件夹拷贝到项目app中,位置与java目录同级。如下图:

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_11

 注意:SDK升级时,data下资源需要同时更新。

2)导出apps文件

 打开我们需要在本地运行的uniapp项目,生成本地打包App资源,生成成功后将NewUIApp\unpackage\resources下的资源复制到Android Studio项目的assets\apps中。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_12

3)修改dcloud_control.xml文件 

修改dcloud_control.xml中的appid为拷贝过来的uni-app的id,确保dcloud_control.xml中的appid与manifest.json中的id与文件夹名一致,如下图所示:

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uniapp打包的ios应用打开白屏_13

稍等配置还没有完成,现在运行只会提示 Appkey is not configured...。

4)证书配置 

下面我们要为这个app配置证书,获取appkey。打开dcloud开发者中心 / 我的应用,找到需要集成的应用,注意这里需要管理员权限。

点击“Android云端证书”生成一个新证书,生成完成。点击“证书详情”我们需要将MD5、SHA1、SHA256、别名、证书密码信息复制出来,在后面的配置中需要使用到,点击“下载证书”将证书复制到的Android Studio项目app文件夹下。

点击“各平台信息”新增应用信息,输入信息后保存。再创建【离线打包Key】,好了。截至目前,我们的证书和appkey都生成好了。

5)配置AppKey

 打开Androidmanifest.xml, 导航到Application节点,创建meta-data节点,name为dcloud_appkey,value为申请的AppKey如下:

<application...>
    <meta-data android:name="dcloud_appkey" android:value="离线打包Key"/>
</application>

Android studio项目build.gradle中配置签名路径及密码。  

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_14

如果出现白屏问题,请检测appid是否一致。 如果在appid一致的情况下仍旧出现白屏现象,请确保Androidmanifest.xml中manifest节点下的package属性与build.gradle中的applicationId一致! 如果appid一致的情况下依旧白屏,请确保ndk配置为armeabi-v7a或者arm64-v8a或者x86.

配置终于完成了,运行起来吧。

四、第三方SDK集成

1、第三方SDK接入

下载需要接入的第三方 SDK,并获取相应的 AppId 等其他信息。

在 Android studio 项目中创建一个 module,我这里选择的是 Android Libray,name都按规则起名不用和uniapp项目包名相同。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_15

将 SDK 包中libs目录下的文件放在刚才创建Module的libs目录下,并配置依赖如下。

dependencies {
    // 扩展module主要依赖库,必须引入
    compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs')
    // 第三方SDK中libs下的依赖包(本地)
    implementation(name: 'beizi_ad_sdk_3.5.0.9', ext: 'aar')
    implementation(name: 'beizi_fusion_sdk_4.90.4.11', ext: 'aar')
    // 需要的其他依赖包
    implementation 'com.geyifeng:immersionbar:3.0.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'androidx.core:core:1.7.0'
}

如果出现找不到依赖包,请配置下maven库,具体maven库地址需要接入的 SDK 文件中找找。如果找不到.arr,那么请在settings.gradle中配置 flatDir { dir './module/libs'}。

2、编写插件类

 这里就不在展示具体的代码内容了,给大家展示先一些关键点。

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_Android_16

3、混淆配置 

Uniapp原生插件是通过反射调用,具体的混淆配置可以在 Dcloud 提供的Android 离线SDK 的Demo中复制,然后再将第三方 SDK 中的混淆也复制到该文件中。

-keepattributes InnerClasses,Signature,Exceptions,Deprecated,*Annotation*

-dontwarn android.**
-keep class android.** {*;}
-keep class com.google.** {*;}
-keep class com.android.** {*;}
-dontwarn org.apache.**
-keep class org.apache.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.google.zxing.** {*;}

#-libraryjars libs/alipaySdk.jar
-dontwarn com.alipay.**
-keep class com.alipay.** {*;}
-keep class com.ut.device.** {*;}
-keep class com.ta.utdid2.** {*;}

#-libraryjars libs/eventbus-3.jar
-keep class org.greenrobot.eventbus.** { *; }
-keep class de.greenrobot.event.** { *; }
-keep class de.greenrobot.dao.** {*;}

-keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
}

-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}
#-libraryjars libs/wechat.jar
-keep class com.tencent.** {*;}

#-libraryjars libs/glide.jar
-keep class com.bumptech.glide.** {*;}

-dontwarn com.xiaomi.**
-keep class com.xiaomi.** {*;}
-keep class com.mi.** {*;}
-keep class com.wali.** {*;}
-keep class cn.com.wali.** {*;}
-keep class miui.net.**{*;}
-keep class org.xiaomi.** {*;}
-keep class com.mi.*** {*;}
-keep class demo.csm.*** {*;}

#保留位于View类中的get和set方法
-keepclassmembers public class * extends android.view.View{
    void set*(***);
    *** get*();
}
#保留在Activity中以View为参数的方法不变
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
#保留实现了Parcelable的类名不变,
-keep class * implements android.os.Parcelable{
    public static final android.os.Parcelable$Creator *;
}
#保留R$*类中静态成员的变量名
-keep class **.R$* {*;}

-dontwarn android.support.**
-keep class **.R$styleable{*;}

#uniapp插件配置
-keep public class * extends io.dcloud.weex.AppHookProxy{*;}
-keep public class * extends io.dcloud.feature.uniapp.UniAppHookProxy{*;}
-keep public class * extends io.dcloud.feature.uniapp.common.UniModule{*;}
-keep public class * extends io.dcloud.feature.uniapp.ui.component.UniComponent{*;}

4、Activity

 有的时候我们可能需要打开原生的 Activity,创建一个新的 Activity 类和原生 Android 的写法没有区别,这里直接展示如何调起原生 Activity。

@UniJSMethod(uiThread = true)
public void openSplashAD() {
    if (mUniSDKInstance != null && mUniSDKInstance.getContext() instanceof Activity) {
        Intent intent = new Intent(mUniSDKInstance.getContext(), 新的Activity.class);
        ((Activity) mUniSDKInstance.getContext()).startActivity(intent);
    }
}

 还需要在 module 的 AndroidManifest.xml,这样才能正确调起。

// AndroidManifest.xml
<application>
    <activity android:name=".新创建的Activity" />
</application>

@xml/network_security_config,那么在 app/AndroidManifest.xml 中进行配置,具体可以参考 uni原生插件包格式。

 5、参数可视化配置

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_android_17

在 app/AndroidManifest.xml 中添加 meta-data 节点,插件开发时可以通过代码获取 android:value属性值:

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_uni-app_18

那么如何使用呢,请看代码:

try {
    ApplicationInfo metaInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
    int appId = metaInfo.metaData.getInt("APPID");
    xxx.init(mUniSDKInstance.getContext(), String.valueOf(appId));
} catch (Exception e) {
    UniLogUtils.e("[插件-Error]: 初始化SDK异常");
}

五、Android离线打包使用插件 

1、插件资源配置

uniapp打包的ios应用打开白屏 uniapp离线打包白屏_xml_19

2、在assets目录下创建dcloud_uniplugins.json文件

插件配置信息请参考插件配置文档或插件配置文件package.json 关于package.json请参考:《Android uni-app原生插件开发文档》。

{
  "nativePlugins": [{
      "plugins": [{
          "type": "module",
          "name": "定义的插件名称",
          "class": "插件中的类路径及类名称"
        }]
    }]
}

使用注意:

  1. HBuilderX在生成本地打包资源时,不需要“制作自定义基座”,manifest.json也不用选择使用“本地插件”。
  2. 在需要调起的页面中 uni.requireNativePlugin 导入插件,调起插件内方法即可。
  3. Android Studio生成的插件 *.arr,需要在app的build.gradle中做依赖,否则插件将无法正常使用。dcloud_uniplugins.json 应该是等同于 HBuilderX中插件的package.json。

如果出现Duplicate class com.google.common*请在app的build.gradle 中配置,例如:

dependencies {
    ...
    implementation project(path: ':mio_module')
}

configurations {
    all {
        exclude group: 'com.google.guava', module: 'listenablefuture'
    }
}