Uniapp 原生插件开发

自从用了 uniapp 之后,腿不酸了,腰不疼了,一口气爬五楼不费劲了。但是,uniapp 虽好,也有解决不了的问题。用了好多好多天的功夫终于调通了 unipush,能够将消息推送到华为手机上了。

然鹅,消息推送下来之后,系统会自动增加桌面图标的角标数字。然后每收到一条消息这个就会+1,再之后,就看到这个数字不断的增加。uni 官方提供了设置角标的api:

plus.runtime.setBadgeNumber(3);

看起来简单粗暴,人畜无害。实际效果呢,就是 iOS 系统上成功了,最起码这个是有效果的,然而再安卓系统上就芭比了。啥用都没有,不过这个倒是也不算出乎意料。

安卓系统的角标设置,简单来说分为两类,一种是标准的,所谓标准就是 google 的原生框架,可以通过原生接口实现,例如 Android Oreo 及以上版本的 Notification Badges。

另外一种就是国情货了,例如各种国产品牌,这些厂商的角标设置本质上是对各个厂商的 launcher 的适配,每个厂商的启动器都不一样。所以就只能通过原生的办法来解决,至于如何解决这个问题,会在后面的文章中写。

上述的这些功能的实现 uni 是解决不了的,就只能通过原生来实现了。此时就需要开发 uni 的原生语言插件,这个插件的本质就是安卓的 module 组件。

创建插件项目最简单的方法就是直接下载官方的 sdk,然后导入示例项目,直接在示例项目上修改或者新建。uni 的官方 sdk 可以通过下面的链接下载:

https://nativesupport.dcloud.net.cn/AppDocs/download/android.html

直接导入 as 工程即可浏览相关的代码和组件。

当然,也可以直接创建一个新的项目,可以参考下面的步骤(前提是已经安装好 android studio,如果还没安装,先去找别的文章看看怎么安装哈):

1.新建安卓项目这个随便选择即可,主要是用于测试一些功能代码:

2.新建 module

3.修改 module 的build.gradle 添加必要的依赖

主要是下面几行:

compileOnly ‘com.alibaba:fastjson:1.2.83’
compileOnly fileTree(dir: ‘libs’, include: [‘*.aar’, ‘*.jar’], exclude: [])
api project(‘:launcherBadge’) # 其他项目依赖,如果没有可以不添加

4.复制 sdk 下的uniapp-v8-release.aar 到 module 的 libs 目录下:

5.编写 module 代码,测试代码如下:

package cn.org.obaby.badge;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

public class babyBadgeModule extends UniModule{
private static final String TAG = “badgeModule”;
public static final String Name = “hello world”;
public void testLoad(){
Log.i(“test”, “hello”);
}
//run ui thread
@UniJSMethod(uiThread = true)
public void testAsyncFunc(JSONObject options, UniJSCallback callback) {
// Log.e(TAG, “testAsyncFunc–“+options);
if(callback != null) {
JSONObject data = new JSONObject();
data.put(“code”, “success”);
callback.invoke(data);
}
}

//run JS thread
@UniJSMethod (uiThread = false)
public JSONObject testSyncFunc(){
JSONObject data = new JSONObject();
data.put(“code”, “success”);
return data;
}
}

注意要 import uni相关的类:

import com.alibaba.fastjson.JSONObject;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

另外 module 要继承自UniModule,如果是Component 扩展类必须继承 UniComponent, 父容器Component(例如ViewGroup组件)则需要继承UniVContainer,具体参考官方教程:https://nativesupport.dcloud.net.cn/NativePlugin/course/android.html

6.编译组件:

菜单 build->build module

此时就会在 build 目录下生成对应的 aar 文件了。

7.在 uniapp 目录nativeplugins下新建插件目录babyBadgeModule(如果没有nativeplugins目录,创建即可):

在插件根目录babyBadgeModule 下新建文件夹 android,以及文件 package.json(注意文件名,这个文件名不知道是复制错了,还是写错了,导致 uni 一直识别不到插件,崩溃。)

将生成的 aar 文件放入 android 目录下。

package.json 文件内容:

{
“name”: “babyBadgeModule”,
“id”: “babyBadgeModule”,
“version”: “1.0.1”,
“description”: “Android 角标插件”,
“_dp_type”:”nativeplugin”,
“_dp_nativeplugin”:{
“android”: {
“plugins”: [
{
“type”: “module”,
“name”: “babyBadgeModule”,
“class”: “cn.org.obaby.badge.babyBadgeModule”
}
],
“integrateType”: “aar”,
“minSdkVersion” : 21
}
}
}

8.选择本地插件

9.uni 代码实现,调用原生插件(下面的代码,调用了两个原生组件):

const babyBadgeModule = uni.requireNativePlugin(‘babyBadgeModule’);
console.log(babyBadgeModule)
babyBadgeModule.setLauncherBadgeCount({COUNT:3},result => {this.showToast(‘test’)});
// require插件名称
const dcRichAlert = uni.requireNativePlugin(‘DCloud-RichAlert’);
// 使用插件
dcRichAlert.show({
position: ‘bottom’,
title: “提示信息”,
titleColor: ‘#FF0000’,
content: “uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架!\n免费的\n免费的\n免费的\n重要的事情说三遍”,
contentAlign: ‘left’,
checkBox: {
title: ‘不再提示’,
isSelected: true
},
buttons: [{
title: ‘取消’
},
{
title: ‘否’
},
{
title: ‘确认’,
titleColor: ‘#3F51B5’
}
]
}, result => {
switch (result.type) {
case ‘button’:
console.log(“callback—button–” + result.index);
break;
case ‘checkBox’:
console.log(“callback—checkBox–” + result.isSelected);
break;
case ‘a’:
console.log(“callback—a–” + JSON.stringify(result));
break;
case ‘backCancel’:
console.log(“callback—backCancel–“);
break;
}
});

10.打自定义基座包:

11.打包完成之后就可以真机调试了,不过如果遇到下面的错误可以尝试将插件名称、目录、id 之类的全部同意再次尝试:

应用【闺蜜圈】已启动
09:00:26.335 [JS Framework] 当前运行的基座不包含原生插件[Baby-Badge],请在manifest中配置该插件,重新制作包括该原生插件的自定义运行基座
09:00:26.364 undefined at pages/index.vue:583
09:00:26.365 [Vue warn]: Error in onLoad hook: “TypeError: Cannot read property ‘setLauncherBadgeCount’ of undefined”

(found at pages/index.vue:1)
09:00:26.365 TypeError: Cannot read property ‘setLauncherBadgeCount’ of undefined

本质上还是插件目录以及文件内容导致的错误,多检查一致性吧,这个确实没什么好办法。

至于调试,再设备上不好调试,可以再原生组件添加 log,通过 logcat 查看相关的日志。至此插件就基本可以用了: