准备工作

  1. Android 离线SDK - 正式版 下载最新的SDK
  2. 解压后看到以下目录结构:

image.png

  1. 将 HBuilder-Hello 项目复制一份放到其他地方,使用Android Studio打开

创建工程

首先创建一个空的Android工程:

File | New | New Project…

📃 Android原生工程搭建 - 图2

选择Empty Activity

📃 Android原生工程搭建 - 图3

为自己的工程取个名字,并配置包名、工程路径等,点击Finish。创建好的工程结构:

📃 Android原生工程搭建 - 图4

修改 app/build.gradle

  1. apply plugin: 'com.android.application'
  2. android {
  3. compileSdkVersion 28
  4. buildToolsVersion '28.0.3'
  5. defaultConfig {
  6. applicationId "com.lizhiboxue.test"
  7. minSdkVersion 23
  8. targetSdkVersion 28
  9. versionCode 100
  10. versionName "1.0.0"
  11. multiDexEnabled true
  12. ndk {
  13. abiFilters 'x86','armeabi-v7a'
  14. }
  15. }
  16. buildTypes {
  17. release {
  18. minifyEnabled false
  19. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  20. }
  21. }
  22. //使用uniapp时,需复制下面代码
  23. /*代码开始*/
  24. aaptOptions {
  25. additionalParameters '--auto-add-overlay'
  26. //noCompress 'foo', 'bar'
  27. ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"
  28. }
  29. /*代码结束*/
  30. }
  31. repositories {
  32. flatDir {
  33. dirs 'libs'
  34. }
  35. }
  36. dependencies {
  37. implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
  38. implementation "com.android.support:support-v4:28.0.0"
  39. implementation "com.android.support:appcompat-v7:28.0.0"
  40. /*uniapp所需库-----------------------开始*/
  41. implementation 'com.android.support:recyclerview-v7:28.0.0'
  42. implementation 'com.facebook.fresco:fresco:1.13.0'
  43. implementation "com.facebook.fresco:animated-gif:1.13.0"
  44. /*uniapp所需库-----------------------结束*/
  45. // 基座需要,必须添加
  46. implementation 'com.github.bumptech.glide:glide:4.9.0'
  47. implementation 'com.alibaba:fastjson:1.1.46.android'
  48. }

包含以下改动:

  1. 将其 targetSdkVersion 配置为28以下(为了适配Android Q,详见适配Android10 / Android Q(API 29)
  2. 将其 targetSdkVersion 配置为21以上,建议此属性值设为23,`io.dcloud.PandoraEntry作为apk入口时 必须设置targetSDKVersion>=21 沉浸式才生效
  3. minSdkVersion必须是19以上,uniapp才起作用
  4. 添加 ndk.abiFilters,以支持指定的架构
  5. 添加aaptOptions节点
  6. 修改dependencies

引入依赖

首先导入HBuilder-Integrate-AS项目中的simpleDemo模块

📃 Android原生工程搭建 - 图5

📃 Android原生工程搭建 - 图6

可以看到以下结构:

📃 Android原生工程搭建 - 图7

然后将simpleDemo模块中的libs复制到app模块中

引入资源

先将我们自己创建的项目中的src删掉,再将simpleDemo中的src复制覆盖到app模块中,可以看到以下目录结构:

📃 Android原生工程搭建 - 图8

启动图及APP名称

位于 res下的目录结构:

📃 Android原生工程搭建 - 图9

drawable下:

  • icon.png 为应用的图标。
  • push.png 为推送消息的图标。
  • splash.png 为应用启动页的图标。

values/string.xml中,里面配置了应用的名称:

  1. <resources>
  2. <string name="app_name">uniapp-android</string>
  3. </resources>

应用配置

assets中,apps下存放了所有的应用,以 应用名/www 的目录结构存放。

📃 Android原生工程搭建 - 图10

可以看出,www目录存放的都是一些编译后的网页资源(没有编译也行,资源是由manifest.json指定)

其中 data 目录中的 dcloud_control.xml 可以指定特定的应用:

  1. <hbuilder>
  2. <apps>
  3. <app appid="HelloH5" appver=""/>
  4. </apps>
  5. </hbuilder>

AndroidManifest.xml

AndroidManifest.xml为应用程序清单,需要将启动页面指定为io.dcloud.PandoraEntry

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="io.dcloud.simple">
  4. <application
  5. android:allowBackup="true"
  6. android:allowClearUserData="true"
  7. android:icon="@drawable/icon"
  8. android:label="@string/app_name"
  9. android:largeHeap="true"
  10. android:supportsRtl="true">
  11. <activity
  12. android:name="io.dcloud.PandoraEntry"
  13. android:configChanges="orientation|keyboardHidden|keyboard|navigation"
  14. android:label="@string/app_name"
  15. android:launchMode="singleTask"
  16. android:hardwareAccelerated="true"
  17. android:theme="@style/TranslucentTheme"
  18. android:screenOrientation="user"
  19. android:windowSoftInputMode="adjustResize" >
  20. <intent-filter>
  21. <action android:name="android.intent.action.MAIN" />
  22. <category android:name="android.intent.category.LAUNCHER" />
  23. </intent-filter>
  24. </activity>
  25. <activity
  26. android:name="io.dcloud.PandoraEntryActivity"
  27. android:launchMode="singleTask"
  28. android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc|fontScale|keyboard"
  29. android:hardwareAccelerated="true"
  30. android:permission="com.miui.securitycenter.permission.AppPermissionsEditor"
  31. android:screenOrientation="user"
  32. android:theme="@style/DCloudTheme"
  33. android:windowSoftInputMode="adjustResize">
  34. <intent-filter>
  35. <category android:name="android.intent.category.DEFAULT" />
  36. <category android:name="android.intent.category.BROWSABLE" />
  37. <action android:name="android.intent.action.VIEW" />
  38. <data android:scheme="h56131bcf" />
  39. </intent-filter>
  40. </activity>
  41. </application>
  42. </manifest>

之后集成各种资源的时候,还需要在 AndroidManifest.xml 中进行权限配置等操作。

启动程序

一切配置完毕,直接运行即可

📃 Android原生工程搭建 - 图11

📃 Android原生工程搭建 - 图12

打包uniapp资源

首先,需要将本地cli项目升级到跟最新版SDK相同的版本:

  1. yarn upgrade

打包本地项目,默认可以使用以下命令:

  1. yarn build:app-plus

实际上是调用了:

  1. cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build

如果需要指定资源生成路径,可以手动指定 UNI_OUTPUT_DIR

  1. cross-env NODE_ENV=production UNI_PLATFORM=app-plus UNI_OUTPUT_DIR=./platforms/android/app/src/main/assets/apps/<appid>/www vue-cli-service uni-build

打包好的资源长这样:
image.png

记住 mainfest.json 中的 appid,在Android原生工程的 assets/apps 中创建相同appid名称的目录,并创建一个www目录,结构如下:
image.png

将打包好的资源全部拷到 <appid>/www 目录下:
image.png

修改data/dcloud_control.xml文件中的appid为项目的appid:
image.png

如果不嫌麻烦,也可以通过HBuilderX打包资源(不推荐):
image.png

应用设置

修改应用名

修改 res/values/strings.xml 的 app_name 字段为应用名称,比如:

  1. <resources>
  2. <string name="app_name">UniappTest</string>
  3. </resources>

注意查看 AndroidManifest.xml 中 activity 的 android:label 属性值是否为 @string/app_name

  1. <activity
  2. android:name="io.dcloud.PandoraEntry"
  3. android:label="@string/app_name"
  4. >
  5. ...

修改包名及应用版本

修改 app/build.gradle 中的 applicationId 字段:

  1. android {
  2. compileSdkVersion 26
  3. buildToolsVersion '28.0.3'
  4. defaultConfig {
  5. applicationId "com.example.test.Hello"
  6. minSdkVersion 19
  7. targetSdkVersion 26
  8. versionCode 100
  9. versionName "0.0.1"
  10. }
  11. ...

修改 AndroidManifest.xml 文件中的 package 属性值为应用包名,versionCode versionName 为版本, 比如:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. package="com.example.test.Hello"
  5. android:versionCode="100"
  6. android:versionName="0.0.1"
  7. >
  8. ...

修改 AndroidManifest.xml 中的 provider 节点下的 android:authorities 属性值为 ${applicationId}.<xxx>,比如

  1. <provider
  2. android:name="io.dcloud.common.util.DCloud_FileProvider"
  3. android:authorities="${applicationId}.fileprovider"
  4. </provider>

可以使用替换:
image.png

  1. from android:authorities="io.dcloud.HelloH5
  2. to: android:authorities="${applicationId}

参考:INSTALL FAILED CONFLICTING PROVIDER问题完美解决方案

修改闪屏页图片和图标

res/drawable-xxhdpi 下的 icon.png push.png splash.png 三个文件进行替换即可。

签名打包

  1. 选择 Build->Generate Signed Bundle/APK...

image.png

  1. 选择APK

image.png

  1. 如果没有证书,选择“创建证书”,如果已经有了证书,则可以选择已有证书

image.png

  1. 选择证书后,选择打包类型为release或debug,Signature Versions建议都选,点击Finish

image.png

  1. 打包成功后的apk:

image.png
默认apk生成路径为 app/release ,如果是debug版本为 app/debug

关于自定义基座

在调试的时候,我们通产会使用自定义基座进行调试,如果使用默认基座,在调试多个应用的时候会出现应用相互覆盖的情况。

自定义基座可以使用上面打包好的APK,将其复制到 dist\debug\android_debug.apk 即可:
image.png

实际上,自定义基座的作用是为了区分不同包名的应用,因为默认基座的包名是确定的:io.dcloud.HBuilder, 因此才会出现相互覆盖的情况。

说到这,其实使用HBuilderX在线打包的话,有一个非常不错的地方:可以任意修改包名。而离线打包可能改包名就比较麻烦了。

安装apk时的错误处理

我在安装打包好的apk时,出现了以下错误:
image.png

错误:more than one device/emulator

错误原因:有多个真机/模拟器连接到电脑。
解决方案:断开多余的真机/ 模拟器,只留一个。

错误:INSTALL_FAILED_UPDATE_INCOMPATIBLE

错误原因:模拟器中包含一个相同的应用,但签名不同。一般是由于之前安装过测试版本的apk,导致安装正式版本的apk时签名不一致。
解决方案:卸载掉之前安装的测试版本。

错误:INSTALL_FAILED_DUPLICATE_PERMISSION

错误原因:已经有其他app申请过这个权限,导致权限重复。一般是由于之前安装过默认项目中的 HBuilder-Hello。
解决方案:卸载掉HBuilder-Hello。

错误:INSTALL_FAILED_ALREADY_EXISTS

错误原因:签名后再次安装会出错。
解决方案:使用 adb install -r xxx.apk 进行安装。

参考资料