自从用了 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: "<a href='https://uniapp.dcloud.io/' value='Hello uni-app'>uni-app</a> 是一个使用 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 查看相关的日志。至此插件就基本可以用了: