
【经验分享】uniappX中实现类似pinia-plugin-persist-uni的本地数据缓存
主要的实现方法
export function defineStore<T>(name : string, obj : T) : T {
let storage = uni.getStorageSync(name);
if (storage instanceof UTSJSONObject) {
let data = JSON.parse<T>(JSON.stringify(storage));
if (data != null) {
let newVal = data as T;
obj = reactive(newVal);
}
}
watch(obj as any, () => {
uni.setStorage({
key: name,
data: obj as any
});
}, {
deep: true
})
return obj;
}
调用示例:
type UserStore = {
initReady : boolean;
userInfo: UTSJSONObject;
}
export const app = defineStore("app", reactive<UserStore>({
initReady: false,
userInfo:{}
}))
页面中app.xxx就是响应式,参考官方文档:https://doc.dcloud.net.cn/uni-app-x/tutorial/store.html#%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E4%B8%8E%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86
如果没有这种处理,app每次启动的时候,状态都会重置。加了后数据就能本地持久化了。
主要的实现方法
export function defineStore<T>(name : string, obj : T) : T {
let storage = uni.getStorageSync(name);
if (storage instanceof UTSJSONObject) {
let data = JSON.parse<T>(JSON.stringify(storage));
if (data != null) {
let newVal = data as T;
obj = reactive(newVal);
}
}
watch(obj as any, () => {
uni.setStorage({
key: name,
data: obj as any
});
}, {
deep: true
})
return obj;
}
调用示例:
type UserStore = {
initReady : boolean;
userInfo: UTSJSONObject;
}
export const app = defineStore("app", reactive<UserStore>({
initReady: false,
userInfo:{}
}))
页面中app.xxx就是响应式,参考官方文档:https://doc.dcloud.net.cn/uni-app-x/tutorial/store.html#%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E4%B8%8E%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86
如果没有这种处理,app每次启动的时候,状态都会重置。加了后数据就能本地持久化了。

【TuiPlus】简洁高效 uniapp x UI组件库重磅发布,原生uts插件加持,保障流畅体验,助力快速开发,打造优质原生应用。
项目介绍
> TuiPlus UI组件库 —— 全面兼容最新设计理念。本次重构不仅着眼于功能的提升,更深入探索用户体验的无限可能。我们的组件库致力于打造一个既全面又精致的UI设计平台,强调设计的精致度和扩展性,始终将用户体验放在首位。在细节的打磨上,我们精益求精,自豪地呈现——TuiPlus UI组件库。
> 创新与差异 —— 新版增加了UTS版图表,裁剪等众多组件,我们的专注点在于提供丰富且独特的组件。每一款组件都是经过匠心独运的设计和优化,确保性能卓越。特别是我们的UTS图表组件,采用高性能的canvas技术,实现了无需webview嵌套的纯canvas绘制,带来了行业领先的流畅度和响应速度。TuiPlus UI组件库全面支持iOS、Android以及Web/H5三端,无缝适配多种屏幕尺寸和形态,包括长屏、宽屏、PC、折叠屏和横屏,满足不同场景下的多样化需求。
!
TuiPlus文档地址:https://life.yundie.xyz/t-uvue-ui/docs/index.html
功能特性快速了解
TuiPlus扫码下载体验
web在线体验
安卓下载链接
项目介绍
> TuiPlus UI组件库 —— 全面兼容最新设计理念。本次重构不仅着眼于功能的提升,更深入探索用户体验的无限可能。我们的组件库致力于打造一个既全面又精致的UI设计平台,强调设计的精致度和扩展性,始终将用户体验放在首位。在细节的打磨上,我们精益求精,自豪地呈现——TuiPlus UI组件库。
> 创新与差异 —— 新版增加了UTS版图表,裁剪等众多组件,我们的专注点在于提供丰富且独特的组件。每一款组件都是经过匠心独运的设计和优化,确保性能卓越。特别是我们的UTS图表组件,采用高性能的canvas技术,实现了无需webview嵌套的纯canvas绘制,带来了行业领先的流畅度和响应速度。TuiPlus UI组件库全面支持iOS、Android以及Web/H5三端,无缝适配多种屏幕尺寸和形态,包括长屏、宽屏、PC、折叠屏和横屏,满足不同场景下的多样化需求。
!
TuiPlus文档地址:https://life.yundie.xyz/t-uvue-ui/docs/index.html
功能特性快速了解
TuiPlus扫码下载体验
web在线体验
安卓下载链接

uni-app-x记账App完整源码&ApiFox接口实战项目
简介
掌握真实项目开发技能!
本源码提供了一个完整的、已经实现的记账应用程序,使用了流行的uni-app-x框架进行前端构建,配合Apifox定义的API接口完成所有前后端交互逻辑。这不仅是一个学习如何在uni-app-x中创建高效、用户友好的界面的机会,更是一次深入了解实际项目开发流程的宝贵经验。
适合人群
无论是初学者还是有一定基础的开发者,这套源码都是提升技能的理想选择。对于那些渴望深入理解uni-app-x以及移动应用开发的人来说,这无疑是一笔值得投资的知识财富。


uniappx 离线打包(主要是使用android studio 调试代码,而不是使用云打包次数)
参考文档
uni-app x 原生 SDK Android 版
文档中的flatDir { dirs('./plugins/') }
单引号需要改成双引号,否则会报错
Uniappx 离线打包配置
社区这位老哥的文章配合官方的文档一起使用比较好。
华为 ScanKit Example
这里我参考的是DefaultView-kotlin
懒人版:直接下载我的示例项目。
android studio example
正式开始
下载 android studio 2023.2.1 Patch 2
最新版或许也可以,不过尽量保持一致好吧
记得安装到其他盘,c 盘足够大可以无视
修改 gradle 安装路径,c 盘足够大可以无视
先添加一下环境变量
点击左上角的图标,点击 File,点击 setting
找到 Gradle,替换路径点击 Apply,点击 OK
JDK
Gradle JDK 17
创建一个 hello world 项目
File->New->New Project
项目信息,尽量保持一致,点击 Finish
创建好之后就是这样的
修改一下Gradle Version 和 Android Gradle Plugin Version
点击File-> Project Structure
先换代理然后点击Sync Project with Gradle Files (这个应该就是拉依赖的意思)
https\://mirrors.cloud.tencent.com/gradle/
启动项目先看看效果
<font color=red>图片中usb调试写错了use</font>
good呀 启动成功了
创建uniappx模块
以下操作请打开官方文档操作,方便复制文字内容
官网文档
社区文档
复制SDK/libs 到 uniappx/libs
<font color=red>这里不要全部都复制,会报错,请按照官网说的来。图片说明我就不改了</font>
在 uniappx下的build.gradle 文件中添加以下依赖
继续在 uniappx下的build.gradle 文件中添加 aaptOptions
将上面下载的sdk里的plugins文件夹复制到项目根目录(和uniappx同层)
在uniappx模块的build.gradle下添加插件io.dcloud.uts.kotlin的依赖
修改项目的settings.gradle
修改项目的gradle.properties
修改app模块下的AndroidMainfest.xml
修改uniappx模块下的AndroidMainfest.xml
继续修改app模块的build.gradle
到这里已经配置的差不多了,接下来配置uts模块插件,也就是我们的华为scanKit
新建uts模块
File->New->New Module
在项目的build.gradle中添加依赖
在x-scan模块的build.gradle中添加依赖
修改uniappx模块的build.gradle
修改app模块的build.gradle
继续修改settings.gradle 添加华为maven仓地址
修改x-scan模块下的AndroidMainfest.xml
最后打开hbuilderx
选择发行->app-android/ios 本地打包->生成本地打包app资源
然后只需要选择android即可
将与appid同名的文件夹复制到uniappx/src/main/assets/apps下
将unpackage/resources/app-android/uniappx/app-android/src下的所有文件复制到uniappx/src/main/java下
将unpackage/resources/app-android/uni_modules/x-scan/utssdk/app-android/src下的文件夹复制到
x-scan/src/main/java下
运行
用手机扫码测试出现扫码结果
正常情况下你可以在x-scan/src/main/java/index.kt中调试你的代码,然后同步到hbuilderx中,全部完成之后可以使用云打包项目即可
报错总结
- Could not resolve all dependencies for configuration ':classpath'.
我这边是maven配置的地址将http改成https - Minimum supported Gradle version is 7.3.3. Current version is 5.6.4.
按照提示升级一下 - 使用chooseImage会报错
将uniappx sdk中的uni-media-release.aar复制到libs中即可。这里的libs就是上面说的libs
参考文档
uni-app x 原生 SDK Android 版
文档中的flatDir { dirs('./plugins/') }
单引号需要改成双引号,否则会报错
Uniappx 离线打包配置
社区这位老哥的文章配合官方的文档一起使用比较好。
华为 ScanKit Example
这里我参考的是DefaultView-kotlin
懒人版:直接下载我的示例项目。
android studio example
正式开始
下载 android studio 2023.2.1 Patch 2
最新版或许也可以,不过尽量保持一致好吧
记得安装到其他盘,c 盘足够大可以无视
修改 gradle 安装路径,c 盘足够大可以无视
先添加一下环境变量
点击左上角的图标,点击 File,点击 setting
找到 Gradle,替换路径点击 Apply,点击 OK
JDK
Gradle JDK 17
创建一个 hello world 项目
File->New->New Project
项目信息,尽量保持一致,点击 Finish
创建好之后就是这样的
修改一下Gradle Version 和 Android Gradle Plugin Version
点击File-> Project Structure
先换代理然后点击Sync Project with Gradle Files (这个应该就是拉依赖的意思)
https\://mirrors.cloud.tencent.com/gradle/
启动项目先看看效果
<font color=red>图片中usb调试写错了use</font>
good呀 启动成功了
创建uniappx模块
以下操作请打开官方文档操作,方便复制文字内容
官网文档
社区文档
复制SDK/libs 到 uniappx/libs
<font color=red>这里不要全部都复制,会报错,请按照官网说的来。图片说明我就不改了</font>
在 uniappx下的build.gradle 文件中添加以下依赖
继续在 uniappx下的build.gradle 文件中添加 aaptOptions
将上面下载的sdk里的plugins文件夹复制到项目根目录(和uniappx同层)
在uniappx模块的build.gradle下添加插件io.dcloud.uts.kotlin的依赖
修改项目的settings.gradle
修改项目的gradle.properties
修改app模块下的AndroidMainfest.xml
修改uniappx模块下的AndroidMainfest.xml
继续修改app模块的build.gradle
到这里已经配置的差不多了,接下来配置uts模块插件,也就是我们的华为scanKit
新建uts模块
File->New->New Module
在项目的build.gradle中添加依赖
在x-scan模块的build.gradle中添加依赖
修改uniappx模块的build.gradle
修改app模块的build.gradle
继续修改settings.gradle 添加华为maven仓地址
修改x-scan模块下的AndroidMainfest.xml
最后打开hbuilderx
选择发行->app-android/ios 本地打包->生成本地打包app资源
然后只需要选择android即可
将与appid同名的文件夹复制到uniappx/src/main/assets/apps下
将unpackage/resources/app-android/uniappx/app-android/src下的所有文件复制到uniappx/src/main/java下
将unpackage/resources/app-android/uni_modules/x-scan/utssdk/app-android/src下的文件夹复制到
x-scan/src/main/java下
运行
用手机扫码测试出现扫码结果
正常情况下你可以在x-scan/src/main/java/index.kt中调试你的代码,然后同步到hbuilderx中,全部完成之后可以使用云打包项目即可
报错总结
- Could not resolve all dependencies for configuration ':classpath'.
我这边是maven配置的地址将http改成https - Minimum supported Gradle version is 7.3.3. Current version is 5.6.4.
按照提示升级一下 - 使用chooseImage会报错
将uniappx sdk中的uni-media-release.aar复制到libs中即可。这里的libs就是上面说的libs

uniapp x 正式打包后 页面无法加载
在小米 14 上跳转会员中心能正常跳转 小米10和小米pad5上无法正常显示页面 直接白屏
在小米 14 上跳转会员中心能正常跳转 小米10和小米pad5上无法正常显示页面 直接白屏

uniapp X 中处理uts和web-view通信中包含中文和其他特殊字符的json
场景: UTS 和 web-view 通信时传输json 中包含中文或其他特殊字符
如果单纯使用atob 和 btob 无法处理包含的中文,可以使用 TextEncoder和 TextDecoder编码解码
UTS 发送数据时:
let v1 = uni.createWebviewContext("web-view")
let dataStr:string = JSON.stringify(jdata as UTSJSONObject)
// 转uint8array 直接传!!!!!!!!!
let encoder = new TextEncoder()
let u8arry = encoder.encode(dataStr)
console.log('getOcrData -----> 向网页发送数据' ,u8arry)
v1?.evalJS(testrece("${u8arry}")
)
UTS 接收数据时:
// 解码
let str = recMessage[0]["data"] as string
let strAry: string[] = str.split(',')
let setAry: number[] = []
//循环strary 写入setARY
strAry.forEach(element => {
setAry.add(parseInt(element))
})
let utf8decoder = new TextDecoder();
let rststr = utf8decoder.decode(Uint8Array.from(setAry))
console.log('接收的转换-----', rststr.toString())
web-view中接收uint8array并解析json:
// 尝试解码
// 1. 将字符串按 ',' 分割,并转换为数字数组
let strArray = str.split(',').filter(Boolean); // 去掉空字符串
let byteArray = new Uint8Array(strArray.map(Number)); // 转换为 Uint8Array
let decoder = new TextDecoder('utf-8')
try {
let jsonStr = decoder.decode(byteArray)
let jsonObj = JSON.parse(jsonStr)
// uts内打印日志
uni.postMessage({
data: {
event: 'consolelog',
data: 转码失败.${jsonObj.id}
}
})
} catch (error) {
// uts内打印日志
uni.postMessage({
data: {
event: 'consolelog',
data: 转码失败.${error.message}
}
})
}
web-view中编码Json发送:
let jsonObj = {
"id": "1234567890",
"name": "张三",
"age": 25,
"gender": "男",
}
let encoder = new TextEncoder()
let encodedData = encoder.encode(JSON.stringify(jsonObj))
let byteArrayString = Array.from(encodedData).join(',')
uni.postMessage({
data: {
event: 'test',
data: byteArrayString
}
})
Json 数据完整完美显示!
场景: UTS 和 web-view 通信时传输json 中包含中文或其他特殊字符
如果单纯使用atob 和 btob 无法处理包含的中文,可以使用 TextEncoder和 TextDecoder编码解码
UTS 发送数据时:
let v1 = uni.createWebviewContext("web-view")
let dataStr:string = JSON.stringify(jdata as UTSJSONObject)
// 转uint8array 直接传!!!!!!!!!
let encoder = new TextEncoder()
let u8arry = encoder.encode(dataStr)
console.log('getOcrData -----> 向网页发送数据' ,u8arry)
v1?.evalJS(testrece("${u8arry}")
)
UTS 接收数据时:
// 解码
let str = recMessage[0]["data"] as string
let strAry: string[] = str.split(',')
let setAry: number[] = []
//循环strary 写入setARY
strAry.forEach(element => {
setAry.add(parseInt(element))
})
let utf8decoder = new TextDecoder();
let rststr = utf8decoder.decode(Uint8Array.from(setAry))
console.log('接收的转换-----', rststr.toString())
web-view中接收uint8array并解析json:
// 尝试解码
// 1. 将字符串按 ',' 分割,并转换为数字数组
let strArray = str.split(',').filter(Boolean); // 去掉空字符串
let byteArray = new Uint8Array(strArray.map(Number)); // 转换为 Uint8Array
let decoder = new TextDecoder('utf-8')
try {
let jsonStr = decoder.decode(byteArray)
let jsonObj = JSON.parse(jsonStr)
// uts内打印日志
uni.postMessage({
data: {
event: 'consolelog',
data: 转码失败.${jsonObj.id}
}
})
} catch (error) {
// uts内打印日志
uni.postMessage({
data: {
event: 'consolelog',
data: 转码失败.${error.message}
}
})
}
web-view中编码Json发送:
let jsonObj = {
"id": "1234567890",
"name": "张三",
"age": 25,
"gender": "男",
}
let encoder = new TextEncoder()
let encodedData = encoder.encode(JSON.stringify(jsonObj))
let byteArrayString = Array.from(encodedData).join(',')
uni.postMessage({
data: {
event: 'test',
data: byteArrayString
}
})
Json 数据完整完美显示!
收起阅读 »
没有十年脑血栓做不出来这种跨平台设计
<template>
<view>
<image ref="logo" class="logo" src="/static/logo.png"></image>
<text>{{cxtInfo}}</text>
<text>{{text}}</text>
<view class="center">
<canvas id="canvas" class="center" style="width: 200px;height: 200px;border: 1px solid red;" ></canvas>
</view>
<button @click="draw()">测试</button>
</view>
</template>
<script>
export default {
data() {
return {
cxt : null as CanvasRenderingContext2D | null,
cxtInfo:{},
text:"",
title: 'Hello'
}
},
onReady() {
console.info("onReady")
uni.createCanvasContextAsync({
id: 'canvas',
component: getCurrentInstance()?.proxy,
success: (context : CanvasContext) => {
const canvasContext = context.getContext('2d')!;
const canvas = canvasContext.canvas;
let {offsetWidth,offsetHeight} = canvas;
// 处理高清屏逻辑
const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
this.cxtInfo = {offsetWidth,offsetHeight,dpr}
canvas.width = canvas.offsetWidth * dpr;
canvas.height = canvas.offsetHeight * dpr;
canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
this.cxt= canvasContext;
}
})
},
onLoad() {
console.info("onLoad")
},
methods: {
draw(){
const cxt =this.cxt!;
cxt.beginPath();
cxt.lineWidth = 2;
cxt.arc(75, 75, 50, 0, Math.PI * 2, true);
cxt.stroke();
let img=this.$refs["logo"] as UniImageElement;
if(img==null){
return;
}
console.info ("img ",img);
console.info ("img.attributes ",img.attributes);
console.info ("img.src ",img.src);
let attrs= img.attributes ;
console.info ("attrs.size ",attrs.size);
// #ifdef WEB
for(let i=0;i< attrs.length ; i++){
let attr = attrs[i];
console.info ("img.attributes."+attr["name"],"=", attr["value"] );
}
// #endif
// #ifdef APP
attrs.forEach((v,k)=>{ //web平台没有
console.info ("img.attributes."+k,v);
})
// #endif
console.info ("img type",typeof img);
console.info (img instanceof Image);
let lc= img.lastChild;
console.info ("lastChild is not null ",lc!=null);
let bcr=img.getBoundingClientRect();
console.info ("BoundingClientRect ",bcr);
if(img instanceof Image){//安卓
this.text="Image"
cxt.drawImage(img,50,50);
}else if(lc!=null && lc instanceof Image){//Web
this.text="Image.lastChild"
cxt.drawImage(lc,100,100);
}else{//IOS
this.text="new Image"
let image = new Image(bcr.width, bcr.height)
image.onload=( )=>{
console.info("image onload ",typeof image)
cxt.drawImage(image,0,0,100,100);
}
image.src = img.attributes.get("src") as string;
}
}
}
}
</script>
<style>
.logo {
height: 100px;
width: 100px;
margin: 100px auto 25px auto;
}
.title {
font-size: 18px;
color: #8f8f94;
text-align: center;
}
.center {
height: 100%;
flex: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
UniElement Extends UniElement // {src:string ,....}
Image Extends UniElement // {src : string }
CanvasRenderingContext2D
drawImage(imageResource: Image, sx: number, sy: number): void
Image 标签(UniElement )竟然和 Image 对象毫无关系
元素属性 attributes 对象 Map<string, any> 竟然无一方式可以跨平台遍历
且Image标签的src属性在不同平台所在位置还不一样
且 对于 attributes ["src"],attributes .get("src") 两张写法竟然还不等价
lc instanceof Image
如何不在前面排除null 竟然会报错null is not an object (evaluating 'Object.getPrototypeOf(e)')
而不是直接返回false
二进制是每种语言基础中的基础 文件读取 encoding 还给限制死了 只能是 base64 utf-8 然后文档还一边说可以不写 这操作就很魔幻
基本上所有api都支持 success,fail,complete 那么所有 opt 都继承 Iopt<S,E> 不就可以统一包装支持 Promise<S,E>了吗
复杂点如果传入了 success,fail,complete 就不返回 Promise 简单就不论是否传入都返回Promise 让opt中的success,fail,complete优先回调就好了
<template>
<view>
<image ref="logo" class="logo" src="/static/logo.png"></image>
<text>{{cxtInfo}}</text>
<text>{{text}}</text>
<view class="center">
<canvas id="canvas" class="center" style="width: 200px;height: 200px;border: 1px solid red;" ></canvas>
</view>
<button @click="draw()">测试</button>
</view>
</template>
<script>
export default {
data() {
return {
cxt : null as CanvasRenderingContext2D | null,
cxtInfo:{},
text:"",
title: 'Hello'
}
},
onReady() {
console.info("onReady")
uni.createCanvasContextAsync({
id: 'canvas',
component: getCurrentInstance()?.proxy,
success: (context : CanvasContext) => {
const canvasContext = context.getContext('2d')!;
const canvas = canvasContext.canvas;
let {offsetWidth,offsetHeight} = canvas;
// 处理高清屏逻辑
const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
this.cxtInfo = {offsetWidth,offsetHeight,dpr}
canvas.width = canvas.offsetWidth * dpr;
canvas.height = canvas.offsetHeight * dpr;
canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
this.cxt= canvasContext;
}
})
},
onLoad() {
console.info("onLoad")
},
methods: {
draw(){
const cxt =this.cxt!;
cxt.beginPath();
cxt.lineWidth = 2;
cxt.arc(75, 75, 50, 0, Math.PI * 2, true);
cxt.stroke();
let img=this.$refs["logo"] as UniImageElement;
if(img==null){
return;
}
console.info ("img ",img);
console.info ("img.attributes ",img.attributes);
console.info ("img.src ",img.src);
let attrs= img.attributes ;
console.info ("attrs.size ",attrs.size);
// #ifdef WEB
for(let i=0;i< attrs.length ; i++){
let attr = attrs[i];
console.info ("img.attributes."+attr["name"],"=", attr["value"] );
}
// #endif
// #ifdef APP
attrs.forEach((v,k)=>{ //web平台没有
console.info ("img.attributes."+k,v);
})
// #endif
console.info ("img type",typeof img);
console.info (img instanceof Image);
let lc= img.lastChild;
console.info ("lastChild is not null ",lc!=null);
let bcr=img.getBoundingClientRect();
console.info ("BoundingClientRect ",bcr);
if(img instanceof Image){//安卓
this.text="Image"
cxt.drawImage(img,50,50);
}else if(lc!=null && lc instanceof Image){//Web
this.text="Image.lastChild"
cxt.drawImage(lc,100,100);
}else{//IOS
this.text="new Image"
let image = new Image(bcr.width, bcr.height)
image.onload=( )=>{
console.info("image onload ",typeof image)
cxt.drawImage(image,0,0,100,100);
}
image.src = img.attributes.get("src") as string;
}
}
}
}
</script>
<style>
.logo {
height: 100px;
width: 100px;
margin: 100px auto 25px auto;
}
.title {
font-size: 18px;
color: #8f8f94;
text-align: center;
}
.center {
height: 100%;
flex: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
UniElement Extends UniElement // {src:string ,....}
Image Extends UniElement // {src : string }
CanvasRenderingContext2D
drawImage(imageResource: Image, sx: number, sy: number): void
Image 标签(UniElement )竟然和 Image 对象毫无关系
元素属性 attributes 对象 Map<string, any> 竟然无一方式可以跨平台遍历
且Image标签的src属性在不同平台所在位置还不一样
且 对于 attributes ["src"],attributes .get("src") 两张写法竟然还不等价
lc instanceof Image
如何不在前面排除null 竟然会报错null is not an object (evaluating 'Object.getPrototypeOf(e)')
而不是直接返回false
二进制是每种语言基础中的基础 文件读取 encoding 还给限制死了 只能是 base64 utf-8 然后文档还一边说可以不写 这操作就很魔幻
基本上所有api都支持 success,fail,complete 那么所有 opt 都继承 Iopt<S,E> 不就可以统一包装支持 Promise<S,E>了吗
复杂点如果传入了 success,fail,complete 就不返回 Promise 简单就不论是否传入都返回Promise 让opt中的success,fail,complete优先回调就好了
收起阅读 »
Uniappx 离线打包配置
Uniapp-x的离线打包
准备(我的配置)
-
HBuilder X (4.29版本及以上)
-
uniapp x SDK (4.29),是uniapp x的SDK,不要跟uniapp的搞混了,下载地址Uniapp x SDK
-
android studio (2023/2024都行)
其它:gradle版本为8.7。gradle插件版本为8.6.0。kotlin插件版本为1.9.0
1. 新建一个Android空项目
打开 android studio,点击顶部的 New Project –> Phone And Tablet –> No Activity,如下图:出现下面的界面
- Name 是你的项目名称
- Package name是你的包名
- Language 要选择 Kotlin
- Min Sdk 建议21
点击Finsh,这是空项目模板
我这里是gradle构建之后的目录,后面的都是基于构建完成的
- 一般称app为主模块,它下面的 build.gradle.kts 是主模块的编译配置文件,也是项目级别的编译配置文件,一定要跟其它的区分开来
下面的步骤就是跟官网一致了!
2. 新建uni-app x模块
点击File->New->New Module...
点击左侧Templates
的Android Library
。
Language
选择Kotlin
。
Module name
建议设置为uniappx
。
点击Finish
。
构建之后会多出一个uniappx目录
基础库配置
- 在uni-app x模块下新建目录
libs
,跟src
同级别 ,将uts-runtime-release.aar,android-gif-drawable-1.2.28.aar,app-common-release.aar,app-runtime-release.aar,breakpad-build-release.aar,dcloud-layout-release.aar, framework-release.aar,uni-exit-release.aar,uni-getAccessibilityInfo-release.aar,uni-getAppAuthorizeSetting-release.aar,uni-getAppBaseInfo-release.aar, uni-getSystemSetting-release.aar,uni-openAppAuthorizeSetting-release.aar,uni-prompt-release.aar,uni-storage-release.aar,uni-getDeviceInfo-release.aar, uni-getSystemInfo-release.aar,uni-rpx2px-release.aar,uni-theme-release.aar共19个aar拷贝到libs下,参考下图
修改uniappx模块下的build.gradle
- 添加依赖
将下面的依赖信息添加到build.gradle中
dependencies {
···
implementation fileTree(include: ['*.aar'], dir: './libs')
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.appcompat:appcompat:1.0.0"
implementation "androidx.exifinterface:exifinterface:1.3.6"
implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.webkit:webkit:1.6.0"
implementation "com.google.android.material:material:1.4.0"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation "com.alibaba:fastjson:1.2.83"
implementation "com.facebook.fresco:fresco:3.1.3"
implementation "com.facebook.fresco:middleware:3.1.3"
implementation "com.facebook.fresco:animated-gif:3.1.3"
implementation "com.facebook.fresco:webpsupport:3.1.3"
implementation "com.facebook.fresco:animated-webp:3.1.3"
implementation "com.github.bumptech.glide:glide:4.9.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.10"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.8.10"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
implementation "com.squareup.okhttp3:okhttp:3.12.12"
implementation "com.github.getActivity:XXPermissions:18.63"
}
- 添加aaptOptions配置
将aaptOptions配置添加到android节点下
aaptOptions {
additionalParameters '--auto-add-overlay'
ignoreAssetsPattern '!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~'
}
- 修改app主模块的配置(不要漏掉了)
在build.gradle
的dependencies
节点添加下面两行
implementation(fileTree(mapOf("include" to listOf("*.aar"), "dir" to "../uniappx/libs")))
implementation(project(":uniappx"))
配置gradle插件
1.下载的SDK压缩包里面有一个plugins
文件,将它复制到你的项目根目录
2.在项目根目录的build.gradle的顶部添加gradle插件的依赖
buildscript {
dependencies {
classpath(files("plugins/uts-kotlin-compiler-plugin-0.0.1.jar"))
classpath(files("plugins/uts-kotlin-gradle-plugin-0.0.1.jar"))
}
}
- 然后在uniappx模块的build.gradle下添加插件io.dcloud.uts.kotlin的依赖
plugins {
...
id 'io.dcloud.uts.kotlin'
}
修改项目的settings.gradle
- 在项目根路径下的settings.gradle中添加jitpack的maven的仓库地址和本地gradle插件的路径配置
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
...
maven { url = uri("https://jitpack.io") }
flatDir { dirs('./plugins/') }
}
}
修改项目的gradle.properties
- 在项目根路径下的gradle.properties中追加如下内容
android.useAndroidX=true
android.enableJetifier=true
修改app主模块下的AndroidManifest.xml
- 添加activity,将下面内容拷贝到application节点下
完成的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">
<application
android:name="io.dcloud.uniapp.UniApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Offlinenative"
tools:targetApi="31" >
<activity
android:name="io.dcloud.uniapp.UniAppActivity"
android:configChanges="orientation|keyboard|keyboardHidden|smallestScreenSize|screenLayout|screenSize|mcc|mnc|fontScale|navigation|uiMode"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/UniAppX.Activity.DefaultTheme"
android:windowSoftInputMode="adjustResize"
tools:replace="android:label,android:exported,android:theme,android:configChanges,android:windowSoftInputMode,android:screenOrientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
修改uniappx模块下的AndroidManifest.xml
- 添加appid,在application节点下添加
DCLOUD_UNI_APPID
节点
<application>
<meta-data
android:name="DCLOUD_UNI_APPID"
android:value="你的appid" />
</application>
拷贝资源文件
-
导出uni-app x项目的资源文件:选择项目,然后点击:发行 -> 原生App-本地打包 -> 生成本地打包App资源,导出成功之后会在项目的unpackage/resources目录下生成资源文件
-
将app-android目录下与appid对应的目录拷贝到uniappx的
assets/apps
目录下,需要自己先创建
- 拷贝kt文件:需要将
unkackage/resource/app-android/uniappx/app-android/src/
目录下的所有文件拷贝到项目的uniappx
模块下的src/main/java
下,src/main/java
下的包名文件夹可以删掉
如果你的项目没有uts插件,到这一步已经可以使用As运行啦
配置uts插件
资源导出成功之后,uts插件资源位于unpackage/resource/app-android/uni_modules下
为方便区分,uts插件指前端封装的uni_modules插件;android uts插件指根据编译后的uts插件生成的安卓原生模块
新建android uts插件模块,跟新建uniappx
一样,下面以插件wow-scankit
为例子,下面所有都是基于wow-scankit
的配置示例
-
点击左侧Templates的Android Library。
-
Language选择Kotlin。
-
Module name建议与uts插件模块名称一致。
-
点击Finish。
注意:
- Templates一定要选择Android Library。
- Language一定要选择Kotlin。
- Build configuration language建议选择Groovy DSL(build.gradle)。以下教程均按照此模式进行
添加gradle插件
- 在
`wow-scankit
插件模块的build.gradle的plugins节点下添加io.dcloud.uts.kotlin的依赖
plugins {
...
id 'io.dcloud.uts.kotlin'
}
- 添加依赖
将下面内容拷贝到build.gradle中,添加到原有的dependencies节点,不要删掉原有的
dependencies {
compileOnly fileTree(include: ['*.aar'], dir: '../uniappx/libs')
compileOnly fileTree(include: ['*.aar'], dir: './libs')
compileOnly "com.alibaba:fastjson:1.2.83"
compileOnly "androidx.core:core-ktx:1.10.1"
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
}
根据config.json配置应用
如果uts插件的config.json
有内容
下面是插件wow-scankit
的配置
minSdkVersion
在插件wow-scankit
的android节点的defaultConfig的minSdk设置此字段
{
"minSdkVersion": "21",
"dependencies": ["com.huawei.hms:scan:2.12.0.301"]
}
dependencies
在插件wow-scankit
的dependencies 添加 implementation 'com.huawei.hms:scan:2.12.0.301'
- 在项目的
settings.gradle.jks
文件需要添加仓库地址
完整的dependencyResolutionManagement
如下
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://jitpack.io")
}
maven {
url = uri("https://developer.huawei.com/repo/")
}
flatDir {
dirs("./plugins/")
}
}
}
- 将插件添加到
uniappx
模块
implementation project(":wow-scankit")
复制资源(如果有就复制)
libs
将src目录下的所有文件拷贝到android uts插件模块/src/main/java目录下(wow-scankit
插件没有)
assets
将assets文件夹拷贝到wow-scankit
插件模块/src/main/
目录下
res
将res文件夹拷贝到wow-scankit
插件模块/src/main/
目录下。
AndroidManifest.xml
将AndroidManifest.xml
拷贝到wow-scankit
插件模块/src/main/
目录下
添加到主项目
将wow-scankit
插件模块的依赖添加到uniappx模块
的build.gradle的依赖中
implementation project(':wow-scankit')
配置完成后重新构建
如果前面步骤没有出错的话,到这里就已经完成了
Uniapp-x的离线打包
准备(我的配置)
-
HBuilder X (4.29版本及以上)
-
uniapp x SDK (4.29),是uniapp x的SDK,不要跟uniapp的搞混了,下载地址Uniapp x SDK
-
android studio (2023/2024都行)
其它:gradle版本为8.7。gradle插件版本为8.6.0。kotlin插件版本为1.9.0
1. 新建一个Android空项目
打开 android studio,点击顶部的 New Project –> Phone And Tablet –> No Activity,如下图:出现下面的界面
- Name 是你的项目名称
- Package name是你的包名
- Language 要选择 Kotlin
- Min Sdk 建议21
点击Finsh,这是空项目模板
我这里是gradle构建之后的目录,后面的都是基于构建完成的
- 一般称app为主模块,它下面的 build.gradle.kts 是主模块的编译配置文件,也是项目级别的编译配置文件,一定要跟其它的区分开来
下面的步骤就是跟官网一致了!
2. 新建uni-app x模块
点击File->New->New Module...
点击左侧Templates
的Android Library
。
Language
选择Kotlin
。
Module name
建议设置为uniappx
。
点击Finish
。
构建之后会多出一个uniappx目录
基础库配置
- 在uni-app x模块下新建目录
libs
,跟src
同级别 ,将uts-runtime-release.aar,android-gif-drawable-1.2.28.aar,app-common-release.aar,app-runtime-release.aar,breakpad-build-release.aar,dcloud-layout-release.aar, framework-release.aar,uni-exit-release.aar,uni-getAccessibilityInfo-release.aar,uni-getAppAuthorizeSetting-release.aar,uni-getAppBaseInfo-release.aar, uni-getSystemSetting-release.aar,uni-openAppAuthorizeSetting-release.aar,uni-prompt-release.aar,uni-storage-release.aar,uni-getDeviceInfo-release.aar, uni-getSystemInfo-release.aar,uni-rpx2px-release.aar,uni-theme-release.aar共19个aar拷贝到libs下,参考下图
修改uniappx模块下的build.gradle
- 添加依赖
将下面的依赖信息添加到build.gradle中
dependencies {
···
implementation fileTree(include: ['*.aar'], dir: './libs')
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.appcompat:appcompat:1.0.0"
implementation "androidx.exifinterface:exifinterface:1.3.6"
implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.webkit:webkit:1.6.0"
implementation "com.google.android.material:material:1.4.0"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation "com.alibaba:fastjson:1.2.83"
implementation "com.facebook.fresco:fresco:3.1.3"
implementation "com.facebook.fresco:middleware:3.1.3"
implementation "com.facebook.fresco:animated-gif:3.1.3"
implementation "com.facebook.fresco:webpsupport:3.1.3"
implementation "com.facebook.fresco:animated-webp:3.1.3"
implementation "com.github.bumptech.glide:glide:4.9.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.10"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.8.10"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
implementation "com.squareup.okhttp3:okhttp:3.12.12"
implementation "com.github.getActivity:XXPermissions:18.63"
}
- 添加aaptOptions配置
将aaptOptions配置添加到android节点下
aaptOptions {
additionalParameters '--auto-add-overlay'
ignoreAssetsPattern '!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~'
}
- 修改app主模块的配置(不要漏掉了)
在build.gradle
的dependencies
节点添加下面两行
implementation(fileTree(mapOf("include" to listOf("*.aar"), "dir" to "../uniappx/libs")))
implementation(project(":uniappx"))
配置gradle插件
1.下载的SDK压缩包里面有一个plugins
文件,将它复制到你的项目根目录
2.在项目根目录的build.gradle的顶部添加gradle插件的依赖
buildscript {
dependencies {
classpath(files("plugins/uts-kotlin-compiler-plugin-0.0.1.jar"))
classpath(files("plugins/uts-kotlin-gradle-plugin-0.0.1.jar"))
}
}
- 然后在uniappx模块的build.gradle下添加插件io.dcloud.uts.kotlin的依赖
plugins {
...
id 'io.dcloud.uts.kotlin'
}
修改项目的settings.gradle
- 在项目根路径下的settings.gradle中添加jitpack的maven的仓库地址和本地gradle插件的路径配置
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
...
maven { url = uri("https://jitpack.io") }
flatDir { dirs('./plugins/') }
}
}
修改项目的gradle.properties
- 在项目根路径下的gradle.properties中追加如下内容
android.useAndroidX=true
android.enableJetifier=true
修改app主模块下的AndroidManifest.xml
- 添加activity,将下面内容拷贝到application节点下
完成的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">
<application
android:name="io.dcloud.uniapp.UniApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Offlinenative"
tools:targetApi="31" >
<activity
android:name="io.dcloud.uniapp.UniAppActivity"
android:configChanges="orientation|keyboard|keyboardHidden|smallestScreenSize|screenLayout|screenSize|mcc|mnc|fontScale|navigation|uiMode"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/UniAppX.Activity.DefaultTheme"
android:windowSoftInputMode="adjustResize"
tools:replace="android:label,android:exported,android:theme,android:configChanges,android:windowSoftInputMode,android:screenOrientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
修改uniappx模块下的AndroidManifest.xml
- 添加appid,在application节点下添加
DCLOUD_UNI_APPID
节点
<application>
<meta-data
android:name="DCLOUD_UNI_APPID"
android:value="你的appid" />
</application>
拷贝资源文件
-
导出uni-app x项目的资源文件:选择项目,然后点击:发行 -> 原生App-本地打包 -> 生成本地打包App资源,导出成功之后会在项目的unpackage/resources目录下生成资源文件
-
将app-android目录下与appid对应的目录拷贝到uniappx的
assets/apps
目录下,需要自己先创建
- 拷贝kt文件:需要将
unkackage/resource/app-android/uniappx/app-android/src/
目录下的所有文件拷贝到项目的uniappx
模块下的src/main/java
下,src/main/java
下的包名文件夹可以删掉
如果你的项目没有uts插件,到这一步已经可以使用As运行啦
配置uts插件
资源导出成功之后,uts插件资源位于unpackage/resource/app-android/uni_modules下
为方便区分,uts插件指前端封装的uni_modules插件;android uts插件指根据编译后的uts插件生成的安卓原生模块
新建android uts插件模块,跟新建uniappx
一样,下面以插件wow-scankit
为例子,下面所有都是基于wow-scankit
的配置示例
-
点击左侧Templates的Android Library。
-
Language选择Kotlin。
-
Module name建议与uts插件模块名称一致。
-
点击Finish。
注意:
- Templates一定要选择Android Library。
- Language一定要选择Kotlin。
- Build configuration language建议选择Groovy DSL(build.gradle)。以下教程均按照此模式进行
添加gradle插件
- 在
`wow-scankit
插件模块的build.gradle的plugins节点下添加io.dcloud.uts.kotlin的依赖
plugins {
...
id 'io.dcloud.uts.kotlin'
}
- 添加依赖
将下面内容拷贝到build.gradle中,添加到原有的dependencies节点,不要删掉原有的
dependencies {
compileOnly fileTree(include: ['*.aar'], dir: '../uniappx/libs')
compileOnly fileTree(include: ['*.aar'], dir: './libs')
compileOnly "com.alibaba:fastjson:1.2.83"
compileOnly "androidx.core:core-ktx:1.10.1"
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
}
根据config.json配置应用
如果uts插件的config.json
有内容
下面是插件wow-scankit
的配置
minSdkVersion
在插件wow-scankit
的android节点的defaultConfig的minSdk设置此字段
{
"minSdkVersion": "21",
"dependencies": ["com.huawei.hms:scan:2.12.0.301"]
}
dependencies
在插件wow-scankit
的dependencies 添加 implementation 'com.huawei.hms:scan:2.12.0.301'
- 在项目的
settings.gradle.jks
文件需要添加仓库地址
完整的dependencyResolutionManagement
如下
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://jitpack.io")
}
maven {
url = uri("https://developer.huawei.com/repo/")
}
flatDir {
dirs("./plugins/")
}
}
}
- 将插件添加到
uniappx
模块
implementation project(":wow-scankit")
复制资源(如果有就复制)
libs
将src目录下的所有文件拷贝到android uts插件模块/src/main/java目录下(wow-scankit
插件没有)
assets
将assets文件夹拷贝到wow-scankit
插件模块/src/main/
目录下
res
将res文件夹拷贝到wow-scankit
插件模块/src/main/
目录下。
AndroidManifest.xml
将AndroidManifest.xml
拷贝到wow-scankit
插件模块/src/main/
目录下
添加到主项目
将wow-scankit
插件模块的依赖添加到uniappx模块
的build.gradle的依赖中
implementation project(':wow-scankit')
配置完成后重新构建
如果前面步骤没有出错的话,到这里就已经完成了
收起阅读 »
ios提交审核横竖屏报错ERROR ITMS-90474-90475: iPad Multitasking support requires these orientations
ipad横屏会自动旋转配置了
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIRequiresFullScreen</key>
<string>YES</string>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~iphone</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
</dict>
</plist>
需要加上这行配置才不会不会报错
<key>UIRequiresFullScreen</key>
<string>YES</string>
ipad横屏会自动旋转配置了
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIRequiresFullScreen</key>
<string>YES</string>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~iphone</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
</dict>
</plist>
需要加上这行配置才不会不会报错
<key>UIRequiresFullScreen</key>
<string>YES</string>

uniapp-x不支持瀑布流列表,望解决
uniapp-x 希望可以支持最基本,瀑布流,和普通的,一行显示2个或者多个item的情况 这也算最基本的列表功能了吧
uniapp-x 希望可以支持最基本,瀑布流,和普通的,一行显示2个或者多个item的情况 这也算最基本的列表功能了吧

uniapp x 数据类型
uniapp x 数据类型那块太难用了,不像js也不像java,玩了两天。放弃了,map list太难用了。先改改吧,还有接口太少,抓紧更新,代码为了适配,写的像屎一样。
uniapp x 数据类型那块太难用了,不像js也不像java,玩了两天。放弃了,map list太难用了。先改改吧,还有接口太少,抓紧更新,代码为了适配,写的像屎一样。