<原创声明>本文首发于微信公众号,具有原创标识,秉着知识共享、互帮互助的原则欢迎大家的转载,但转载须有度,还请加出处,请尊重别人的劳动成果,谢谢。
uni-app是啥,套用官方的话,它是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。
当你使用uni-app来对项目进行开发时,免不了使用各种各样的插件,官方的插件市场(https://ext.dcloud.net.cn)虽有上千款,但是一个项目如果是高度自定义的话,那难免对插件的功能有着特定的需求,这时就需要自己开发原生插件来满足需要了。
官方早早注意到了这点,对原生插件开发的定义也很贴合实际:当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力。
但是不可否认的是,官方给出的文档还是过于跳脱简洁。对老手而言,上手似乎没有什么难度,对新手就不怎么友好了。
所以重点就来了,本次演示uni原生插件安卓开发流程,以Module扩展为例,绝对是从头到尾的“一条龙服务”,当然为了更好的理解开发思路,文章还是依照官方文档来的。
下面步入正题。
第一步,开发环境的准备
JAVA环境配置:
以windows10为例,cmd进入自己电脑命令提示符,输入java -version查看自己的jdk版本,官方文档中提示jdk版本应在1.7及以上,最优1.8,如果达不到标准,自行下载相关版本配置好环境变量即可。
jdk下载路径:
https://www.oracle.com
https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
AndroidStudio配置:
验证AndroidStudio是否配置成功,具体流程可参照《HBuildeX安卓离线打包教程》相关图文第一步。若测试项目能够显示“Hello World!”并且无报错,代表项目成功跑起,AndroidStudio基本配置完成。
AndroidStudio下载路径:
https://developer.android.google.cn/studio/index.html
http://www.android-studio.org/
App离线SDK下载:
在DCloud官网下载好安卓离线SDK,解压以待使用。
Android离线SDK下载路径:
https://nativesupport.dcloud.net.cn/AppDocs/download/android
官方uni原生插件开发教程(android)网址:
https://nativesupport.dcloud.net.cn/NativePlugin/course/android
第二步,创建自定义项目与引入官方项目
打开AndroidStudio,在菜单栏选择File>New>New Project,创建自定义项目。
因为第一步代表AndroidStudio已经测试完成,能够正常使用,所以我们直接创建No Activity项目,点击Next。
填写项目名、包名,以及Minimum API Level(有疑惑可参照《HBuilderX安卓离线打包》图文第一步)
项目创建完毕,为了更好的使用,我们把它转到Project视图。
接下来创建要开发的模块,本文在Module和Component 扩展中选择Module扩展为例。
点击File>New>New Module...
选择Android Library,点击Next
自定义Library名和包名(这里是com.test.testplugin)点击Finish
创建完毕后如图所示
接下来导入官方提供的uni插件原生项目,里面的东西我们待会儿要用到
File>New>Import Project...
项目在官方的离线SDK中,我是直接把它拷到AndroidStudio默认存放路径了,这样方便导入。
如图,点击OK
导入成功,我们参照里面的uniplugin_module模块
配置刚刚创建的testplugin的build.gradle(testplugin)信息
如图,将dependencies下默认生成的依赖注释掉,添加uni-app所需库依赖
compileOnly 'com.android.support:recyclerview-v7:28.0.0'
compileOnly 'com.android.support:support-v4:28.0.0'
compileOnly 'com.android.support:appcompat-v7:28.0.0'
再添加后续用到的json解析库
compileOnly 'com.alibaba:fastjson:1.1.46.android'
接下来导入uniapp-release.aar插件,它是扩展module主要依赖库(此时也可以把离线打包用到的另外三个插件一起导入)
在app>libs目录下导入插件,如图
回到刚刚创建的testplugin的build.gradle(testplugin)中,接下来进行导入aar需要的配置操作
添加
repositories {
flatDir {
dirs 'libs'
}
}
到dependencies{}上方,注意,不要把它放到android{}里了
在dependencies内添加
compileOnly fileTree(dir: '../app/libs', include: ['uniapp-release.aar'])
上述配置全览
点击Sync Now或者Sync Project with Gradle Files进行同步处理(同步失败或过慢请参照uni-app离线打包图文)
官方文档提醒:
工程gradle配置的为gradle-4.6-all版本,使用的是新版本的依赖方式。如果您使用的是老版本的gradle,可根据以下链接进行修改依赖方式。
https://blog.csdn.net/wangliblog/article/details/81366095
第三步,原生插件的开发
以扩展Module为例,参照官方UniPlugin-Hello-AS工程中的uniplugin_module模块,如图创建类TestModule
TestModule需要继承WXModule类
Module扩展注意事项:
weex扩展API for android:
http://weex.apache.org/cn/guide/extend-android.html
下面简单举个例子:
如图创建testText()方法,通过options.getString(XX)获取vue或nvue页面传送到插件的name和age信息。
name和age为空则反馈输入无效信息,不为空判断age,age小于0和大于30不合格,在合格范围(0~30)内,年龄大于0且小于10时返回信息自动补0。
接下来在本地注册插件
在app>src>main目录下创建assets文件夹
在app>src>main>assets目录下创建dcloud_uniplugins.json文件,我们也可以拷贝刚刚导入官方的项目中的json文件,对其稍作修改。
对dcloud_uniplugins.json中的内容做出适当修改
参照相关说明
(注册方法一)
因为当前只举了Module扩展的一个例子,所以要删除掉多余元素,完成后如图
(注册方法二)
对创建的Module扩展testplugin进行操作,在 src>main>java>插件包名(这里是com.test.testplugin)目录下创建类TestModule_AppProxy
TestModule_AppProxy类要实现AppHookProxy接口,在onCreate()方法中添加weex注册相关参数或填写插件需要在启动时初始化的逻辑。
在hooksClass节点填入你创建的实现AppHookProxy接口的实体类的完整名称 (注:有些需要初始化操作的需求可以在此处添加逻辑,无特殊操作仅使用第一种方式注册即可无需集成AppHookProxy接口)
注册完毕,开始打包插件
在Gradle>testplugin>Tasks>other目录下找到assembleRelease,双击等待系统编译出扩展module的aar文件
注意:官方文档中是选择Gradle--->插件module--->Tasks--->build--->assembleRelease编译module的aar文件,在新版本的AndroidStudio中,assembleRelease和assembleDebug被转移到other目录下。
成功后在testplugin>build>outputs>aar目录下就可以找到相关插件了
第四步,HBuilderX导入和使用本地插件
如图,创建uni-app默认项目TestModule
参照官方文档中的目录规范,将刚才打包的插件放到nativeplugins>插件文件夹名称(我的是Test-Module)>android目录下,没有相关目录就一步步创建。
创建package.json——uni原生插件描述文件,放到插件文件夹名称目录下,与android文件夹并列
package.json官方描述文档:
https://nativesupport.dcloud.net.cn/NativePlugin/course/package
按照要求填写相关信息
注意:插件标识id必须在对应android和ios节点下plugins中进行注册,与name字段值一致。name下的class是注册插件的类名,也要填对。
这里因为只有android插件,就把ios节点全部删掉,在这里直接注释的话是无效的。
还有要注意的一点:插件标识id一定要与插件文件夹名称一致,不然在云打包时会提示插件不合法:该插件在nativePlugins目录下不存在。
在manifest.json下配置App原生插件
勾选并确认
parameters信息根据需求配置
接下来在HBuilderX内对项目中的index.vue文件(在pages>index目录下)做出一定更改,以便后续测试开发的原生插件。
如图,利用
const XXX= uni.requireNativePlugin('XXX-XXX');
形式在vue或者nvue中引入本地插件,“XXX-XXX”为package.json中的id。
解释修改后的index.vue:
代码中有两个输入框,分别输入name和age,点击提交按钮,调用methods中的testText()方法,将输入的name和age的值传到插件进行处理。
第五步,运行项目的三种方式
通过在线打包制作自定义基座来运行
在HBuilderX里选定项目
运行(R)>运行到手机或模拟器(N)>制作自定义调试基座(P)
配置App云端打包信息
在这里使用了自有证书,这是之前图文中创建的,密码123456
下面选中了打自定义调试基座(iOS的safari调试需要用苹果开发证书打包),因为是要测试,所以不要点到打正式包上了
云端打包
提交到云端服务器
打包完成
打包成功后需要在下图位置确保开启自定义调试基座功能:
可以在项目unpackage下看到打包后的测试apk文件
启动模拟器,运行
模拟器启动成功
进入测试项目
输入姓名tom和年龄9(大于0小于10前面自动补0)测试插件,点击提交
反馈提交结果
把年龄改为31(插件设置年龄范围为0~30),反馈如下
测试成功
附加
如果Module扩展模块做出了更改,顺着Gradle>testplugin>Tasks>other目录
选择assembleDebug或者assembleRelease双击等待系统编译成aar文件
编译完成后,在testplugin>build>outputs>aar中找到相关文件,复制粘贴到相关目录下,替换之前的插件
再进行云打包基座调试即可
因为通过离线打包制作自定义基座来运行和通过AndroidStudio来运行条件基本一致,所以前期先把共同条件配置好(与离线打包高度相似)
配置运行条件
①配置AndroidManifest.xml
在app>src>main下配置AndroidManifest.xml文件
将其修改为
然后继续下一步,添加内容到application节点(建议复制官方文档里的,下面的复制粘贴后排版会比较乱)。
android:name="io.dcloud.PandoraEntry" android:configChanges="orientation|keyboardHidden|keyboard|navigation" android:label="@string/app_name" android:launchMode="singleTask" android:hardwareAccelerated="true" android:theme="@style/TranslucentTheme" android:screenOrientation="user" android:windowSoftInputMode="adjustResize" >
android:name="io.dcloud.PandoraEntryActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc|fontScale|keyboard" android:hardwareAccelerated="true" android:permission="com.miui.securitycenter.permission.AppPermissionsEditor" android:screenOrientation="user" android:theme="@style/DCloudTheme" android:windowSoftInputMode="adjustResize">
添加完成后如下图
AndroidManifest.xml配置完毕
②引入打包资源
进入下载好后的安卓离线SDK文件夹,在目录
2.7.5\[email protected]_20200519\SDK\libs
下找到
lib.5plus.base-release.aar
miit_mdid_1.0.10.aar
uniapp-release.aar
四个文件,复制到自定义的新文件夹方便使用
在目录
2.7.5\[email protected]_20200519\SDK\assets
下找到data文件夹,打开可以发现下图几个文件。
可以发现,较上一版本2.6.16少了dcloud1.dat和dcloud2.dat两个文件
官方文档中给出了说明:dcloud1.dat、dcloud2.dat为uni-app所需资源,2.7.0之后已不再需要,升级时需要删除,可以减少apk大小。
返回上一级,复制data文件夹如上一步操作,为了方便与四个文件放到一起。
如图,在发行(P)选项>原生APP-本地打包(L)中选择生成本地打包App资源(R)。
显示导出成功,顺着路径将自己项目id名的文件夹拷贝,放到上一步自定义的文件夹下,方便使用。
这里我的项目id是__UNI__179390F,就把它放到如图位置
打开AndroidStudio,如下图将
lib.5plus.base-release.aar
miit_mdid_1.0.10.aar
三个文件复制粘贴到libs目录下
(第二步添加依赖时已经导入uniapp-release.aar了)
如下图在build.gradle(app)中添加引用资源
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "com.android.support:support-v4:28.0.0"
implementation "com.android.support:appcompat-v7:28.0.0"
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.facebook.fresco:fresco:1.13.0'
implementation "com.facebook.fresco:animated-gif:1.13.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.alibaba:fastjson:1.1.46.android'
自带的依赖进行注释
添加
接下来在
android{
...
}
内添加
aaptOptions {
additionalParameters '--auto-add-overlay'
ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"
}
再回到build.gradle(app)页面最上边,配置app版本号。
compileSdkVersion为编译版本,buildToolsVersion为构建工具版本,applicationId为创建时的包名,minSdkVersion为兼容最小的版本号,targetSdkVersion为目标版本,有兴趣的可以百度一下三者之间的区别和联系。
注意,官方文档中标注“App离线SDK minSdkVersion最低支持19,小于19在部分4.4以下机型上将无法正常使用。”
versionCode需要设定一个数值,一般初始为1,更新版本时versionCode的值需要做出更改,每次都要比前一个设置的值大,否则无法正常安装。
versionName一般填写主版本号次版本号和修正号,如图中的“1.0.0”为最初版本号,其余的可以自行查阅。
然后同步处理
同步完成
把刚刚转移到自定义文件夹下的data文件夹拷贝到app>src>main>assets目录文件夹下。
继续在刚刚创建的assets文件夹下创建apps文件夹,把刚刚进行本地打包资源处理后的文件(我的是__UNI__179390F)拷贝到apps文件夹下。
③引入本地原生插件
在build.gradle(app)下添加
implementation project(':testplugin')
用来引入本地插件
在dependencies{}上方添加
repositories {
flatDir {
dirs 'libs'
}
}
注意:跟第二步情况一样,不要把它放在android{}内
同步处理
④自定义基座的配置
在app目录下,将assets下apps文件夹中的manifest.json文件和data文件夹中的dcloud_control.xml文件打开,确保manifest.json中的id和dcloud_control.xml中的appid一致(不一致会出现白屏等状况)。
并设置根节点的debug和syncDebug为true
条件配置完毕
名称配置
在app>src>main>res>values配置strings.xml文件,打开xml文件,与刚刚引入本地打包资源的里的manifest.json文件比较,发现名字不一致,遂把strings.xml里的name改为“TestModule”。
(注:manifest.json文件在
assets>apps>__UNI__179390F>www目录下)
通过离线打包制作自定义基座来运行
开始打debug包,方法Ⅰ
如图,在Gradle>app>Tasks>other目录下找到assembleDebug或者assembleRelease,双击等待系统编译完成
编译完成后,在app>build>outputs>apk文件夹下即可找到debug和release相关apk文件
开始打debug包,方法Ⅱ
如图,在菜单栏Build > Build Bundle(s)/APK (s)下选择Build APK(s),等待系统编译
编译完成,在app>build>outputs>apk>debug路径下即可找到相关apk文件
如此,debug打包完成
将app-debug.apk文件复制到项目unpackage>debug目录下,如果里面存在android_debug.apk文件,就先删除掉,再将app-debug.apk文件名称改为android_debug即可(也可先更名,粘贴进去直接复制替换掉)
运行(R)>运行手机或模拟器(N)>运行相关设备,成功运行
测试结果如下图:
测试成功
通过AndroidStudio来运行
切换到模拟器选项
点击Run 'app'运行
项目成功打开,测试结果如下:
到了这一步已经可以正常打包进行实机测试了
打包流程
用到了之前图文中创建testLove.jks文件,密码都是123456
这一块不熟的可以参照我以前图文,包括在AndroidStudio内进行app图标设置
实机测试
测试成功
附:如果运行时报device support x86 but apk only supports armeabi-v7a错误,进入到build.gradle(app)中,在
android{
defaultConfig {
//要导入地方
}
}
内导入
ndk {
abiFilters 'x86','armeabi-v7a'
}
即可
总结
本次演示项目用的是vue文件,而官方的unipluginDemo进行插件演示时是在nvue条件下进行的,在很多方面,nvue能做的其实比vue更多,但nvue在css的写法限制性较强,也有一些缺点,具体可见
https://uniapp.dcloud.io/use-weex
演示以Module扩展举例,官方的Demo里还有uniplugin_component和uniplugin_richalert两个例子,我怕放一起看着会乱,就先一个一个来咯。如果时间充足的话,视频演示会在后续放出。
最后