uni-app之android原生插件开发
一 插件简介
1.1 当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力。
1.2 插件类型有两种,Module模式和Component模式
- Module模式:能力扩展,无嵌入窗体的UI控件。大部分插件都是属于此类,比如调用计步器API。代码写法为通过js进行require,然后调用该插件对象的方法。如涉及一些弹出框、全屏ui,也仍然属于Module模式。类似于前端里的js sdk。
- Component模式:在窗体中内嵌显示某个原生ui组件。比如窗体局部内嵌某个地图厂商的map组件,上下混排其他前端内容,就需要把这个原生地图sdk封装为Component模式。代码写法与vue组件相同,在template里写组件标签。类似于前端里的vue组件。
1.3 插件的使用:原生插件开发后,可以上插件市场,也可以不上。如内部使用,则无需上架插件市场。 如需上插件市场,则必须按指定格式压缩为zip包
二 插件的开发
2.1 插件必须在uni-sdk的基础上进行开发,可以快速的下载离线uni-sdk,导入UniPlugin-Hello-AS示例工程,也可以自己新建一个原生android项目,拷贝不要的包和资源进行开发。
2.2 离线uni-sdk下载地址: https://nativesupport.dcloud.net.cn/AppDocs/download/android.html,里面包含必要资源和示例工程。
2.3 上一篇已经新建了一个android项目,并离线打包成功了uni资源项目,下面就在这基础上开发插件

2.4 androidStudio项目右击新建一个插件Module

2.5 选择library,填写module名字,点击finish

2.6 然后在app的build.gradle里面依赖该module
implementation project(':mylibrary')

2.6 module里面build.gradle配置相关依赖库
uniapp-v8-release.aar是扩展module主要依赖库,必须导入此依赖库
compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs')
com.alibaba:fastjson 也是必须的也依赖上,后面json通信会用到
implementation 'com.alibaba:fastjson:1.2.83'
同时为了避免和主app冲突,将全部依赖类型换为compileOnly,意思只本module有效
dependencies {
compileOnly 'androidx.appcompat:appcompat:1.5.0'
compileOnly 'com.google.android.material:material:1.6.1'compileOnly 'com.alibaba:fastjson:1.2.83'
compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs')
}
2.7 创建TestModule类,必须继承 UniModule 类
- 扩展方法必须加上@UniJSMethod (uiThread = false or true) 注解。UniApp 会根据注解来判断当前方法是否要运行在 UI 线程,和当前方法是否是扩展方法。
- UniApp是根据反射来进行调用 Module 扩展方法,所以Module中的扩展方法必须是 public 类型。
示例:创建两个方法
public class TestModule extends UniModule {private static final String TAG = "TestModule";//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;}}
2.8 注册插件,在androidStudio的assets里面新建dcloud_uniplugins.json,并注册插件信息
{"nativePlugins": [{"plugins": [{"type": "module","name": "TestModule","class": "com.juai.plugin_module.TestModule"}]}]
}

2.9 回调事件UniJSCallback:JS调用时,有的场景需要返回一些数据,比如以下例子,返回x、y坐标。
invoke调用javascript回调方法,此方法将在调用后被销毁。invokeAndKeepAlive调用javascript回调方法并保持回调活动以备以后使用。
三 上面简单的插件module就写好了,下面做一个简单的测试
3.1 在uni-app项目页面里面写一个按钮,调用该插件。首先加一个按钮,并设置点击事件。
<button type="primary" @click="testAsyncFunc">testAsyncFunc</button>
3.2 获取刚写好的TestModule插件
var testModule = uni.requireNativePlugin("TestModule")
3.3 methon里面,注册点击事件,并调用原生插件方法
testAsyncFunc() {// 获取 modulevar testModule = uni.requireNativePlugin("TestModule")// 调用异步方法testModule.testAsyncFunc({'name': 'unimp','age': 1},e => {uni.showToast({title: JSON.stringify(e),icon:'none'});})
}
3.4 完整vue示例
<template><view class="content"><image class="logo" src="/static/logo.png"></image><view class="text-area"><text class="title">{{title}}</text></view><button type="primary" @click="testAsyncFunc">testAsyncFunc</button></view>
</template><script>export default {data() {return {title: 'Hello'}},onLoad() {},methods: {testAsyncFunc() {// 获取 modulevar testModule = uni.requireNativePlugin("TestModule")// 调用异步方法testModule.testAsyncFunc({'name': 'unimp','age': 1},e => {uni.showToast({title: JSON.stringify(e),icon:'none'});})}}}
</script><style>.content {display: flex;flex-direction: column;align-items: center;justify-content: center;}.logo {height: 200rpx;width: 200rpx;margin-top: 200rpx;margin-left: auto;margin-right: auto;margin-bottom: 50rpx;}.text-area {display: flex;justify-content: center;}.title {font-size: 36rpx;color: #8f8f94;}
</style>
3.5 打包app资源
3.7 替换androidStudio项目中的资源包

3.8 运行项目看到刚的按钮已经有了,点击android会获取uni的json数据,说明插件调用成功

3.9 同时也可以看到androidStudio控制台已经有日志打出,插件调用成功

四 插件打包
4.1 上面只是android原生离线调试可以,那怎样在uni中来使用这个原生插件呢。首先要生成插件的aar包,在androidStudio侧边栏找到Gradle工具 -> 再找到项目的Task目录 -> other目录 -> 点击assembleRelease,等待编译结束


4.2 可以看到再插件module的build下面生成了一个aar

4.3 在uni的项目根目录下创建 nativeplugins 文件夹 -> 再创建插件名目录TestModule -> 再创建android目录,把刚才的aar拷贝到android目录下面

4.4 在插件目录下面创建一个pakage.json来配置插件信息

{"name": "TestModule","id": "TestModule", // 插件标识"version": "1.0.0","description": "插件描述信息","_dp_type":"nativeplugin","_dp_nativeplugin":{"android": {"integrateType":"aar","plugins": [{"type": "module","name": "TestModule", //id为前缀"class": "com.juai.plugin_module.TestModule"}]}}
}
4.5 这个示例比较简单,如果有so库,和jar包,还需要配置这些信息,完成目录结构如下

4.6 在manifest.json中识别本地插件

4.7 可以看到有这个插件

4.8 直接标准基座运行是不行的,找不到插件。需要云打包后进行测试


4.9 选择发行 -> 云打包

配置密钥信息

4.10 打包出错,说package.json里面不能包含注释,那我们去掉再试试


4.11 重新云打包出现新错误,大概是说最小androidSDk版本太高了,让最小19


4.12 那就把minSDK调整为19,重新生成aar,替换原来的aar

或者在插件module清单文件AndroidManifest.xml里面添加库的冲突配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-sdk tools:overrideLibrary="com.bun.miitmdid,com.juai.plugin_module" />..............</manifest>
4.13 可以看到打包成功


4.14 我们将该apk运行手机看下,可以正常运行

4.15 注意:云打包是有次数的,十来次今天就不能云打包了。所以为了节省次数可以选择自定义基座运行或者安心打包

五 组件Component开发
5.1 组件Component的介绍:
- Component 扩展 实现特别功能的 Native 控件
- Component 不支持代码中 new Component 创建对象。无法正常使用
5.2 androidStudio新建组件module

5.3 添加必须的依赖
compileOnly 'com.alibaba:fastjson:1.2.83'
compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs')
5.2 创建TestComponent类,Component 扩展类必须继承 UniComponent, 父容器Component(例如ViewGroup组件)则需要继承UniVContainer
public class TestText extends UniComponent<TextView>
5.3 UniComponent的initComponentHostView回调函数。构建Component的view时会触发此回调函数。
@Override
protected TextView initComponentHostView(@NonNull Context context) {TextView textView = new TextView(context);textView.setTextSize(20);textView.setTextColor(Color.BLACK);return textView;
}
5.4 Component 对应的设置属性的方法必须添加注解 @UniComponentProp(name=value(value is attr or style of dsl))
@UniComponentProp(name = "tel")
public void setTel(String telNumber) {getHostView().setText("tel: " + telNumber);
}
5.5 在app的build.gradle里面添加该组件依赖
implementation project(':ModuleComponent')
5.6 在app的assets的dcloud_uniplugins.json文件里面注册组件
{"plugins": [{"type": "component","name": "myText","class": "com.juai.modulecomponent.TestText"}]
}
5.7 在uni项目里面添加TestText组件
<template><myText ref="telText" tel="12305" style="width:200;height:100" @onTel="onTel" @click="myTextClick"></myText>
</template>
5.8 在uni项目的methods里面添加点击事件
methods: { myTextClick(e) {this.$refs.telText.clearTel();}
}
5.9 完整uni示例
<template><div><myText ref="telText" tel="12305" style="width:200;height:100" @onTel="onTel" @click="myTextClick"></myText></div>
</template>
<script> export default { methods: { myTextClick(e) {this.$refs.telText.clearTel();}} }
</script>
5.10 uni打包app资源

5.11 复制资源包到androidStudio项目的assets里面

5.12 运行出现该组件说明成功,同样打包aar,复制到uni项目里面的nativeplugins目录,并配置pakage.json

5.13 云打包就可以安装真机上运行了

六 发布插件到DCloud市场
6.1 上面说了怎样使用本地插件,我们也可以发布插件到市场,这样就能通过远程依赖使用该插件 。发布插件地址:https://ext.dcloud.net.cn/publish
6.2 填写名字等基础信息

6.3 打包插件,生成zip压缩包


6.4 上传插件使用说明md文本


6.5 发布插件,可能会提示未包含插件内容,是因为上面填写的插件id,和压缩包的插件id不一致。我们改为一致


6.6 因为发布插件必须这样格式,我们就修改uni项目中的插件ID名字

6.7 重新发布,可以看到发布成功了

6.7 插件发布成功,就跟项目ID关联着,在HBuilder里面选择该插件就可以了

相关文章:
uni-app之android原生插件开发
一 插件简介 1.1 当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力。 1.2 插件类型有两种,Module模式和Component模式 Module模式:能力扩展&…...
javaee spring aop实现事务 项目结构
spring配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"http://www.springframewo…...
9.9校招 实习 内推 面经
绿泡*泡: neituijunsir 交流裙 ,内推/实习/校招汇总表格 1、自动驾驶一周资讯 -理想汽车计划进军自动驾驶卡车领域,宝马联合亚马逊开发下一代自动驾驶平台,丰田汽车重组自动驾驶和人工智能子公司 自动驾驶一周资讯 -理想汽车…...
互联网医院App开发:构建医疗服务的技术指南
互联网医院App的开发是一个复杂而具有挑战性的任务,但它也是一个充满潜力的领域,可以为患者和医疗专业人员提供更便捷的医疗服务。本文将引导您通过一些常见的技术步骤来构建一个简单的互联网医院App原型,以了解该过程的基本概念。 技术栈选…...
阅读分享--重读Youtube深度学习推荐系统论文,字字珠玑,惊为神文
重读Youtube深度学习推荐系统论文,字字珠玑,惊为神文 https://zhuanlan.zhihu.com/p/52169807 废话不多说,下面就跟大家分享一下两次拜读这篇论文的不同体验和收获。 第一遍读这篇论文的时候,我想所有人都是冲着算法的架构去的,在深度学习推荐系统已经成为各大公司“基本…...
使用Python操作CSV文件,方便又快捷
概念 CSV是逗号分隔值或者字符分割值,其文件以纯文本形式存储表格数据。 CSV文件可以用文本文件或者转换成EXCEL(直接用EXCEL也可以,但是可能会有一些问题)打开。因此更适合通过CSV文件进行程序之间转移表格数据。 应用场景 需…...
深入探索KVM虚拟化技术:全面掌握虚拟机的创建与管理
文章目录 安装KVM开启cpu虚拟化安装KVM检查环境是否正常 KVM图形化创建虚拟机上传ISO创建虚拟机加载镜像配置内存添加磁盘能否手工指定存储路径呢?创建成功安装完成查看虚拟机 KVM命令行创建虚拟机创建磁盘通过命令行创建虚拟机手动安装虚拟机 KVM命令行创建虚拟机-…...
javaee springMVC model的使用
项目结构图 pom依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…...
Spring与Docker:如何容器化你的Spring应用
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
试图替代 Python 的下一代AI编程语言:Mojo
文章目录 为什么叫 Mojo ?Python 家族的一员,MojoPython 的好处:Python 兼容性Python 的问题移动和服务器部署:Python 子集和其他类似 Python 的语言: Mojo 是一种创新的编程语言,结合了 Python 的可用性和…...
【数据结构】栈、队列和数组
栈、队列和数组 栈队列数组数组的顺序表示和实现顺序表中查找和修改数组元素 矩阵的压缩存储特殊矩阵稀疏矩阵 栈 初始化 #define MaxSize 50//栈中元素的最大个数 typedef char ElemType;//数据结构 typedef struct{int top;//栈顶指针ElemType data[MaxSize];//存放栈中的元…...
python算法调用方案
1、python算法部署方案 (1)独立部署 算法端和应用端各自独立部署。 使用WSGI(flask)web应用A包装算法,并发布该应用A。 应用端B 通过httpclient调用算法应用A中的api接口。 (2)统一部署 算法…...
《微服务架构设计模式》第二章
文章目录 微服务架构是什么软件架构是什么软件架构的定义软件架构的41视图模型为什么架构如此重要 什么是架构风格分层式架构风格六边形架构风格微服务架构风格什么是服务什么是松耦合共享类库的角色 为应用程序定义微服务架构识别操作系统根据业务能力进行拆分业务能力定义了一…...
taro vue3 ts nut-ui 项目
# 使用 npm 安装 CLI $ npm install -g tarojs/cli 查看 Taro 全部版本信息 可以使用 npm info 查看 Taro 版本信息,在这里你可以看到当前最新版本 npm info tarojs/cli 项目初始化 使用命令创建模板项目: taro init 项目名 taro init myApp …...
【群答疑】jmeter关联获取上一个请求返回的字符串,分割后保存到数组,把数组元素依次作为下一个请求的入参...
一个非常不错的问题,来检验下自己jmeter基本功 可能有同学没看懂题,这里再解释一下,上面问题需求是:jmeter关联获取上一个请求返回的字符串,分割后保存到数组,把数组元素依次作为下一个请求的入参 建议先自…...
Shell 函数详解(函数定义、函数调用)
Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可。 Shell 中的函数和C、Java、Python、C# 等其它编程语言中的函数类似,只是在语法细节有所差别。 Shell 函数定义的语…...
git-命令行显示当前目录分支
1. 打开家目录.bashrc隐藏文件,找到如下内容 forlinxubuntu:~$ vi ~/.bashrcif [ "$color_prompt" yes ]; thenPS1${debian_chroot:($debian_chroot)}\[\033[01;32m\]\u\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ elsePS1${debian_chroot:($debi…...
pgsql 报错 later table “drop column” is not supported now
报错 使用pgsql执行下面的SQL报错 alter table test_user drop clolumn name;报错信息: later table “drop column” is not supported now。 报错原因 hologres pgsql的数据库: 删除列目前还是灰度测试阶段,需要在sql前加上set hg_ex…...
如何制定私域流量布局计划?
01 确定目标用户群体 首先,明确目标用户是私域流量布局的基础。可以通过市场调研、用户画像和数据分析等方式,了解目标用户的年龄、性别、兴趣爱好等特征,为后续精准营销奠定基础。 02 选择合适的私域流量渠道 根据目标用户群体的特点&…...
yolov8 模型部署--TensorRT部署-c++服务化部署
写目录 yolov8 模型部署--TensorRT部署1、模型导出为onnx格式2、模型onnx格式转engine 部署 yolov8 模型部署–TensorRT部署 1、模型导出为onnx格式 如果要用TensorRT部署YOLOv8,需要先使用下面的命令将模型导出为onnx格式: yolo export modelyolov8n.p…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
