一、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。
** 注意 **:这里的MiniSDK的版本需要与uniapp项目中的manifest.json中所配置的版本相一致;UTS开发uniapp插件,那么Language请选择Kotlin。
项目创建成功将会打开Android Studio IDE窗口,这个时候Android Studio 会自动刷新项目以及Gradle build,停掉它。先不让它build,我们还没有配置Gradle、SDK、JDK版本。
1、配置SDK
点击File — settings...,打开配置页搜索SDK。
首先,配置 Android SDK 路径点击 Edit,配置路径后下一步直至完成即可。
其次,安装需要的SDK Platforms、SDK Tools,勾选安装即可(建议使用31.0.0)。
2、配置JDK
点击File — settings...,打开配置页搜索Gradle,这里也可以更换Gradle地址(我使用默认地址),选择JDK版本为1.8(uni-app原生插件要求JAVA环境为JDK1.8)。
3、配置Gradle
点击File — Project Structure,打开项目配置,配置如图所示。这里避免 离线打包 或者 制作插件 可能会出现其他原因,故不使用最新的。
Comile Sdk Version选择31,JDK选择1.8,其他项先不动,点击OK后等待安装即可。加入Gradle Build失败,那么请打开settings.gradle(旧版的请在Build.gradle中配置)文件配置其它maven镜像,这里就不做展示了。
4、启动项目
到这里我们项目配置基本完成,先创建一个模拟设备启动试一试。
随便选择一个设备尺寸,下一步。我们刚才配置的SDK选择的是31.0.0,那么我们这里也选择 API Level 31完成,Run App跑起来。
三、配置App离线SDK
1、基础库配置
将App离线SDK目录 \HBuilder-Integrate-AS\simpleDemo\libs下的依赖包都拷贝到项目\app\libs目录下,如图:
创建项目时默认的依赖可以直接删除,配置上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目录同级。如下图:
注意:SDK升级时,data下资源需要同时更新。
2)导出apps文件
打开我们需要在本地运行的uniapp项目,生成本地打包App资源,生成成功后将NewUIApp\unpackage\resources下的资源复制到Android Studio项目的assets\apps中。
3)修改dcloud_control.xml文件
修改dcloud_control.xml中的appid为拷贝过来的uni-app的id,确保dcloud_control.xml中的appid与manifest.json中的id与文件夹名一致,如下图所示:
稍等配置还没有完成,现在运行只会提示 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中配置签名路径及密码。
如果出现白屏问题,请检测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项目包名相同。
将 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、编写插件类
这里就不在展示具体的代码内容了,给大家展示先一些关键点。
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、参数可视化配置
在 app/AndroidManifest.xml 中添加 meta-data 节点,插件开发时可以通过代码获取 android:value属性值:
那么如何使用呢,请看代码:
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、插件资源配置
2、在assets目录下创建dcloud_uniplugins.json文件
插件配置信息请参考插件配置文档或插件配置文件package.json 关于package.json请参考:《Android uni-app原生插件开发文档》。
{
"nativePlugins": [{
"plugins": [{
"type": "module",
"name": "定义的插件名称",
"class": "插件中的类路径及类名称"
}]
}]
}
使用注意:
- HBuilderX在生成本地打包资源时,不需要“制作自定义基座”,manifest.json也不用选择使用“本地插件”。
- 在需要调起的页面中 uni.requireNativePlugin 导入插件,调起插件内方法即可。
- 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'
}
}