HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

限时0.1元!!!iOS、纯血鸿蒙、安卓 获取唯一ID(UUID) 和 iOS钥匙串、鸿蒙AssetStore资产存储

鸿蒙 iOS插件 iOS uts插件 鸿蒙next

# 限时促销:0.1元 (截止8月30日)。

https://ext.dcloud.net.cn/plugin?name=aper-keychainmanager
iOSKeyChain(苹果钥匙串)、鸿蒙AssetStoreKit(资产存储),卸载重装不丢失数据,可用于记录唯一ID、游客登录、用户名、密码
本插件为UTS插件,支持UniappX

包含以下功能:

  1. iOS KeyChain管理器(钥匙串) 读取、写入、删除
  2. 鸿蒙AssetStoreKit管理器(资产管理器) 读取、写入、删除
  3. 安卓、iOS、鸿蒙 唯一ID生成和存储(一般用于游客登录,或记住用户名、密码)

使用过程中如有 疑问 或 建议 或 新需求,欢迎进插件群交流,本插件持续更新中。。。

继续阅读 »

# 限时促销:0.1元 (截止8月30日)。

https://ext.dcloud.net.cn/plugin?name=aper-keychainmanager
iOSKeyChain(苹果钥匙串)、鸿蒙AssetStoreKit(资产存储),卸载重装不丢失数据,可用于记录唯一ID、游客登录、用户名、密码
本插件为UTS插件,支持UniappX

包含以下功能:

  1. iOS KeyChain管理器(钥匙串) 读取、写入、删除
  2. 鸿蒙AssetStoreKit管理器(资产管理器) 读取、写入、删除
  3. 安卓、iOS、鸿蒙 唯一ID生成和存储(一般用于游客登录,或记住用户名、密码)

使用过程中如有 疑问 或 建议 或 新需求,欢迎进插件群交流,本插件持续更新中。。。

收起阅读 »

华为上架审核终于审核通过了

应用上架 华为应用市场

经历了10多次的驳回~~心酸~终于通过了

经历了10多次的驳回~~心酸~终于通过了

针对使用插件过程中遇到的问题与建议

反馈

作为一名新入行学习前端的初学者,在学习了pc端网页的设计后,开始学习小程序的开发。

而在使用过程中,我发现该官网在网页的布局上对待使用者并不友好,例如在使用某些组件时,代码区太小了,而且还是template,script,css分为三个页面,然后挤在一块用分页跳转查,真的很难用。每行代码显示不全也不会跳到下一行,内置的还有个上下左右滑动查看。。。。。

真的非常难用,找个自己需要的代码找半天,无语了都。

继续阅读 »

作为一名新入行学习前端的初学者,在学习了pc端网页的设计后,开始学习小程序的开发。

而在使用过程中,我发现该官网在网页的布局上对待使用者并不友好,例如在使用某些组件时,代码区太小了,而且还是template,script,css分为三个页面,然后挤在一块用分页跳转查,真的很难用。每行代码显示不全也不会跳到下一行,内置的还有个上下左右滑动查看。。。。。

真的非常难用,找个自己需要的代码找半天,无语了都。

收起阅读 »

win电脑发布(上传)ipa文件到appstore经验分享

Appstore上传

最近想发布ipa文件到appstore的时候,发现在app store填写资料的时候,需要xcode或其他mac电脑的软件来上传ipa文件,还需要多种尺寸的ios app的截屏。

这可是难为我们windows电脑的开发者了。

最后,我发现并不需要mac电脑也可以上架的,可以使用香蕉云编来实现。

下面是我上架appstore的经验分享:

先登录苹果开发者平台,点进去app store connect的app管理
新建一个app(假如你还没创建才需要创建),如下图,新建app的时候,套装ID这一项是最重要的,因为代表应用的ID,需要跟我们在hbuilderx填写的appId一模一样才行。

创建完后,你就可以见到app的列表界面有这个app了,如下:

点击app的名字,进去就开始上架了
其中进去第一个界面需要提供屏幕截屏,需要提供很多ios设备的截屏,你可以使用香蕉云编来合成这些截屏。

https://www.yunedit.com/jietu

然后在后面,还需要上传ipa到构建版本,如下图所示:

这里win电脑安装不了xcode这些ide,因此使用香蕉云编来上传:

https://www.yunedit.com/ipasend

进入香蕉云编,提供ipa和平台账号这些信息,就可以上传了:

继续阅读 »

最近想发布ipa文件到appstore的时候,发现在app store填写资料的时候,需要xcode或其他mac电脑的软件来上传ipa文件,还需要多种尺寸的ios app的截屏。

这可是难为我们windows电脑的开发者了。

最后,我发现并不需要mac电脑也可以上架的,可以使用香蕉云编来实现。

下面是我上架appstore的经验分享:

先登录苹果开发者平台,点进去app store connect的app管理
新建一个app(假如你还没创建才需要创建),如下图,新建app的时候,套装ID这一项是最重要的,因为代表应用的ID,需要跟我们在hbuilderx填写的appId一模一样才行。

创建完后,你就可以见到app的列表界面有这个app了,如下:

点击app的名字,进去就开始上架了
其中进去第一个界面需要提供屏幕截屏,需要提供很多ios设备的截屏,你可以使用香蕉云编来合成这些截屏。

https://www.yunedit.com/jietu

然后在后面,还需要上传ipa到构建版本,如下图所示:

这里win电脑安装不了xcode这些ide,因此使用香蕉云编来上传:

https://www.yunedit.com/ipasend

进入香蕉云编,提供ipa和平台账号这些信息,就可以上传了:

收起阅读 »

基于flutter3.32仿微信app聊天模板

flutter

flutter3-chat:基于最新跨平台技术flutter3.32+dart3.8+get_storage+photo_view+toast搭建仿微信App界面聊天项目。包含聊天、通讯录、我的、朋友圈模块。实现发送图文消息、gif大图、长按仿微信语音操作面板、图片预览、红包/朋友圈等功能。

使用技术

  • 框架技术:Flutter3.32+Dart3.8
  • 组件库:material-design3
  • 弹窗组件:showDialog/SimpleDialog/showModalBottomSheet/AlertDialog
  • 图片预览:photo_view^0.15.0
  • 存储组件:get_storage^2.1.1
  • 下拉刷新:easy_refresh^3.4.0
  • toast提示:toast^0.3.0
  • 网址预览组件:url_launcher^6.3.1

项目框架目录

flutter3-chat聊天app模板已经更新到我的原创作品集。

flutter3.32+dart3.8跨平台仿微信聊天app应用

如果想要了解更多项目实现情况,可以去看看下面这篇文章。
最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈

热文推荐

最新版uniapp+vue3+uv-ui跨三端短视频+直播+聊天【H5+小程序+App端】
原创uniapp+vue3+deepseek+uv-ui跨端实战仿deepseek/豆包流式ai聊天对话助手。
vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果
Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
uniapp+vue3酒店预订|vite5+uniapp预约订房系统模板(h5+小程序+App端)
Electron32-Vue3OS桌面版os系统|vue3+electron+arco客户端OS管理模板
tauri2.0-admin桌面端后台系统|Tauri2+Vite5+ElementPlus管理后台EXE程序
Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天应用

继续阅读 »

flutter3-chat:基于最新跨平台技术flutter3.32+dart3.8+get_storage+photo_view+toast搭建仿微信App界面聊天项目。包含聊天、通讯录、我的、朋友圈模块。实现发送图文消息、gif大图、长按仿微信语音操作面板、图片预览、红包/朋友圈等功能。

使用技术

  • 框架技术:Flutter3.32+Dart3.8
  • 组件库:material-design3
  • 弹窗组件:showDialog/SimpleDialog/showModalBottomSheet/AlertDialog
  • 图片预览:photo_view^0.15.0
  • 存储组件:get_storage^2.1.1
  • 下拉刷新:easy_refresh^3.4.0
  • toast提示:toast^0.3.0
  • 网址预览组件:url_launcher^6.3.1

项目框架目录

flutter3-chat聊天app模板已经更新到我的原创作品集。

flutter3.32+dart3.8跨平台仿微信聊天app应用

如果想要了解更多项目实现情况,可以去看看下面这篇文章。
最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈

热文推荐

最新版uniapp+vue3+uv-ui跨三端短视频+直播+聊天【H5+小程序+App端】
原创uniapp+vue3+deepseek+uv-ui跨端实战仿deepseek/豆包流式ai聊天对话助手。
vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果
Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
uniapp+vue3酒店预订|vite5+uniapp预约订房系统模板(h5+小程序+App端)
Electron32-Vue3OS桌面版os系统|vue3+electron+arco客户端OS管理模板
tauri2.0-admin桌面端后台系统|Tauri2+Vite5+ElementPlus管理后台EXE程序
Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天应用

收起阅读 »

副文本编辑器uni居然不支持editorContext.getSelection,而微信小程序却有editorContext.getSelection等等方法

富文本

微信小程序和uni的差异也太大了吧?

微信小程序和uni的差异也太大了吧?

定制一个树形页面,竖着,子级可以分叉

插件需求

已自己开发完成

已自己开发完成

招聘双端原生开发 上海

招聘

插件开发 + uni小程序SDK开发

插件开发 + uni小程序SDK开发

JQL语句使用花括号查询,在支付宝云中会报错

同样的查询语句,在阿里云中正常,在支付宝云直接报错,由于是使用了花括号的写法,但是官方仅仅是不推荐,不代表不能用,真的头大

 const db = uniCloud.database()  
        const rollCallTemp = db.collection('roll-call')  
          .where(`_id=="${ this.rollCallId }"`)  
          .getTemp()  
        const res = await db.collection(rollCallTemp, 'project')  
          .field('title,description,has_password,password,status,start_time,end_time,total_members,responded_count,project_id{project_name,cover,description,start_time,end_time}')  
          .get()  
继续阅读 »

同样的查询语句,在阿里云中正常,在支付宝云直接报错,由于是使用了花括号的写法,但是官方仅仅是不推荐,不代表不能用,真的头大

 const db = uniCloud.database()  
        const rollCallTemp = db.collection('roll-call')  
          .where(`_id=="${ this.rollCallId }"`)  
          .getTemp()  
        const res = await db.collection(rollCallTemp, 'project')  
          .field('title,description,has_password,password,status,start_time,end_time,total_members,responded_count,project_id{project_name,cover,description,start_time,end_time}')  
          .get()  
收起阅读 »

uniapp-x 官方文档 UTSActivityCallback 示例有误

uni-app-x

大标题

官方链接 :https://doc.dcloud.net.cn/uni-app-x/uts/utsactivitycallback.html#UniActivityKeyEventCallback

uvue代码部分缺少变量 cbText,新建 uni_modules插件不能以uts开头,即示例中的 uts-syntaxcase 不可以以这个命名,将其改为 muts-syntaxcase

uts代码代码缺少所有需要引入的库,除了内置库。

缺少以下库

import Bundle from "android.os.Bundle"  
import KeyEvent from "android.view.KeyEvent"  
import WindowManager from "android.view.WindowManager"   
import Menu from "android.view.Menu"  
import ActionMode from "android.view.ActionMode"  
import Configuration from "android.content.res.Configuration"  
import KeyboardShortcutGroup from "android.view.KeyboardShortcutGroup";

完整代码

------uvue页面代码------

<template>  
    <!-- #ifdef APP-ANDROID -->  
    <scroll-view style="flex: 1">  
        <view>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="text-box" scroll-y="true">  
                    <text>{{ text }}</text>  
                </view>  
            </view>  
            <button @tap="activityCallback">注册activity 回调方法</button>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="uni-hello-text">  
                    点击注册activity 回调方法后,可以手动切换其他APP再返回,可在控制台和界面观察事件日志  
                </view>  
            </view>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="text-box" scroll-y="true">  
                    <text>{{ cbText }}</text>  
                </view>  
            </view>  
            <button @tap="unRegActivityCallback">取消注册activity 回调方法</button>  
        </view>  
    </scroll-view>  
    <!-- #endif -->  
</template>  

<script>  
    // #ifdef APP-ANDROID  
    import {  
        UTSAcvitiyLifeCycleCallback,  
        UTSAcvitiyKeyEventCallback,  
        UTSActivityWindowCallback,  
        UTSActivityCallback,  
        UTSActivityComponentCallback,  
        onCallbackChange  
    } from '@/uni_modules/muts-syntaxcase'  
    // #endif  

    import File from 'java.io.File';  
    import Intent from 'android.content.Intent';  

    export default {  
        data() {  
            return {  
                text: '',  
                cbText: "" as string,  
                callback: [] as Any[]  
            }  
        },  
        unmounted() {  
            // #ifdef APP-ANDROID  
            this.unRegActivityCallback()  
            // #endif  

        },  
        methods: {  
            // #ifdef APP-ANDROID  
            // #ifdef UNI-APP-X  
            activityCallback() {  
                var that = this  
                onCallbackChange(function (eventLog : string) {  
                    // 展示捕捉到的声明周期日志  
                    let nextLine = that.cbText + eventLog  
                    that.cbText = nextLine  
                    let nextLineFlag = that.cbText + '\n'  
                    that.cbText = nextLineFlag  
                })  
                let index = getCurrentPages().length - 1  
                let page = getCurrentPages()[index]  
                console.log('page route=' + page.route)  
                this.callback.push(new UTSAcvitiyLifeCycleCallback())  
                this.callback.push(new UTSActivityWindowCallback())  
                this.callback.push(new UTSAcvitiyKeyEventCallback())  
                this.callback.push(new UTSActivityCallback(), page.route)  
                this.callback.push(new UTSActivityComponentCallback())  
                this.callback.forEach((value) => {  
                    if (value instanceof UTSAcvitiyLifeCycleCallback) {  
                        UTSAndroid.onActivityCallback(value, page.route)  
                    }  
                    if (value instanceof UTSActivityWindowCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSAcvitiyKeyEventCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityComponentCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  

                })  
            },  
            unRegActivityCallback() {  
                this.callback.forEach((value) => {  

                    if (value instanceof UTSAcvitiyLifeCycleCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityWindowCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSAcvitiyKeyEventCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityComponentCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                })  
            }  
            // #endif  
            // #endif  
        },  
    }  
</script>

------uts代码------

代码位置:uni_modules/muts-syntaxcase/utssdk/app-android/index.uts

let callback : (eventLog : string) => void = (res) => { };  

export function onCallbackChange(fn : (eventLog : string) => void) {  
    callback = fn  
}  
import Bundle from "android.os.Bundle"  
import KeyEvent from "android.view.KeyEvent"  
import WindowManager from "android.view.WindowManager"   
import Menu from "android.view.Menu"  
import ActionMode from "android.view.ActionMode"  
import Configuration from "android.content.res.Configuration"  
import KeyboardShortcutGroup from "android.view.KeyboardShortcutGroup";  
export class UTSAcvitiyLifeCycleCallback extends UniActivityLifeCycleCallback {  
    constructor() {  
        super()  
    }  
    override onCreate(params : UniActivityParams, savedInstanceState : Bundle | null) {  
        console.log('UTSAcvitiyLifeCycle', 'onCreate', savedInstanceState)  
        callback('onCreate')  
    }  

    override onResume(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onResume', params)  
        callback('onResume')  
    }  
    override onPreResume(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onPreResume', params)  
        callback('onPreResume')  
    }  
    override onStart(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onStart', params)  
        callback('onStart')  
    }  
    override onPreStart(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onPreStart', params)  
        callback('onPreStart')  
    }  
}  
export class UTSAcvitiyKeyEventCallback extends UniActivityKeyEventCallback {  
    constructor() {  
        super()  
    }  
    override onKeyDown(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onKeyDown', params, keyCode, '' + event)  
        callback('onKeyDown')  
    }  
    override onPreKeyDown(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onPreKeyDown', params, keyCode, '' + event)  
        callback('onPreKeyDown')  
    }  
    override onKeyLongPress(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onKeyLongPress', params, keyCode, '' + event)  
        callback('onKeyLongPress')  
    }  
    override onPreKeyLongPress(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onPreKeyLongPress', params, keyCode, '' + event)  
        callback('onPreKeyLongPress')  
    }  
}  

export class UTSActivityWindowCallback extends UniActivityWindowCallback {  
    constructor() {  
        super()  
    }  
    override dispatchPreKeyEvent(params : UniActivityParams, event : KeyEvent | null) {  
        console.log('UTSActivityWindowCallback', 'dispatchPreKeyEvent', params, '' + event)  
        callback('dispatchPreKeyEvent')  
    }  
    override dispatchKeyEvent(params : UniActivityParams, event : KeyEvent | null) {  
        console.log('UTSActivityWindowCallback', 'dispatchKeyEvent', params, '' + event)  
        callback('dispatchKeyEvent')  
    }  
    override  onWindowAttributesChanged(params : UniActivityParams, attrs : WindowManager.LayoutParams) {  
        console.log('UTSActivityWindowCallback', 'onWindowAttributesChanged', '' + attrs)  
        callback('onWindowAttributesChanged')  

    }  
    override onAttachedToWindow(params : UniActivityParams) {  
        console.log('UTSActivityWindowCallback', 'onAttachedToWindow', params)  
        callback('onAttachedToWindow')  

    }  
    override onPanelClosed(params : UniActivityParams, featureId : Int, menu : Menu) {  
        console.log('UTSActivityWindowCallback', 'onPanelClosed', featureId, menu)  
        callback('onPanelClosed')  

    }  
    override onWindowStartingActionMode(params : UniActivityParams, callback : ActionMode.Callback | null) {  
        console.log('UTSActivityWindowCallback', 'onWindowStartingActionMode', callback)  
        callback('onWindowStartingActionMode')  
    }  
    override onProvideKeyboardShortcuts(params : UniActivityParams, data : MutableList<KeyboardShortcutGroup> | null, menu : Menu | null, deviceId : Int) {  
        console.log('UTSActivityWindowCallback', 'onProvideKeyboardShortcuts', data, menu)  
        callback('onProvideKeyboardShortcuts')  
    }  
    override  onPreWindowAttributesChanged(params : UniActivityParams, attrs : WindowManager.LayoutParams) {  
        console.log('UTSActivityWindowCallback', 'onPreWindowAttributesChanged', attrs)  
        callback('onPreWindowAttributesChanged')  
    }  
    override  onPrePanelClosed(params : UniActivityParams, featureId : Int, menu : Menu) {  
        console.log('UTSActivityWindowCallback', 'onPrePanelClosed', featureId, menu)  
        callback('onPrePanelClosed')  
    }  
}  

export class UTSActivityCallback extends UniActivityCallback {  
    constructor() {  
        super()  
    }  
    override onRequestPermissionsResult(params : UniActivityParams, requestCode : Int, permissions : MutableList<String>, grantResults : IntArray) {  
        console.log('UTSActivityCallback', 'onRequestPermissionsResult', params)  
        callback('onRequestPermissionsResult')  
    }  

}  

export class UTSActivityComponentCallback extends UniActivityComponentCallback {  
    constructor() {  
        super()  
    }  
    override onConfigurationChanged(params : UniActivityParams, newConfig : Configuration) {  
        console.log('UTSActivityComponentCallback', 'onConfigurationChanged', params, '' + newConfig)  
        callback('onConfigurationChanged')  
    }  
    override onPreConfigurationChanged(params : UniActivityParams, newConfig : Configuration) {  
        console.log('UTSActivityComponentCallback', 'onPreConfigurationChanged', params, '' + newConfig)  
        callback('onPreConfigurationChanged')  
    }  
}

使用HbuilderX 4.74.2025063012-alpha版本编写

继续阅读 »

大标题

官方链接 :https://doc.dcloud.net.cn/uni-app-x/uts/utsactivitycallback.html#UniActivityKeyEventCallback

uvue代码部分缺少变量 cbText,新建 uni_modules插件不能以uts开头,即示例中的 uts-syntaxcase 不可以以这个命名,将其改为 muts-syntaxcase

uts代码代码缺少所有需要引入的库,除了内置库。

缺少以下库

import Bundle from "android.os.Bundle"  
import KeyEvent from "android.view.KeyEvent"  
import WindowManager from "android.view.WindowManager"   
import Menu from "android.view.Menu"  
import ActionMode from "android.view.ActionMode"  
import Configuration from "android.content.res.Configuration"  
import KeyboardShortcutGroup from "android.view.KeyboardShortcutGroup";

完整代码

------uvue页面代码------

<template>  
    <!-- #ifdef APP-ANDROID -->  
    <scroll-view style="flex: 1">  
        <view>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="text-box" scroll-y="true">  
                    <text>{{ text }}</text>  
                </view>  
            </view>  
            <button @tap="activityCallback">注册activity 回调方法</button>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="uni-hello-text">  
                    点击注册activity 回调方法后,可以手动切换其他APP再返回,可在控制台和界面观察事件日志  
                </view>  
            </view>  
            <view class="uni-padding-wrap uni-common-mt">  
                <view class="text-box" scroll-y="true">  
                    <text>{{ cbText }}</text>  
                </view>  
            </view>  
            <button @tap="unRegActivityCallback">取消注册activity 回调方法</button>  
        </view>  
    </scroll-view>  
    <!-- #endif -->  
</template>  

<script>  
    // #ifdef APP-ANDROID  
    import {  
        UTSAcvitiyLifeCycleCallback,  
        UTSAcvitiyKeyEventCallback,  
        UTSActivityWindowCallback,  
        UTSActivityCallback,  
        UTSActivityComponentCallback,  
        onCallbackChange  
    } from '@/uni_modules/muts-syntaxcase'  
    // #endif  

    import File from 'java.io.File';  
    import Intent from 'android.content.Intent';  

    export default {  
        data() {  
            return {  
                text: '',  
                cbText: "" as string,  
                callback: [] as Any[]  
            }  
        },  
        unmounted() {  
            // #ifdef APP-ANDROID  
            this.unRegActivityCallback()  
            // #endif  

        },  
        methods: {  
            // #ifdef APP-ANDROID  
            // #ifdef UNI-APP-X  
            activityCallback() {  
                var that = this  
                onCallbackChange(function (eventLog : string) {  
                    // 展示捕捉到的声明周期日志  
                    let nextLine = that.cbText + eventLog  
                    that.cbText = nextLine  
                    let nextLineFlag = that.cbText + '\n'  
                    that.cbText = nextLineFlag  
                })  
                let index = getCurrentPages().length - 1  
                let page = getCurrentPages()[index]  
                console.log('page route=' + page.route)  
                this.callback.push(new UTSAcvitiyLifeCycleCallback())  
                this.callback.push(new UTSActivityWindowCallback())  
                this.callback.push(new UTSAcvitiyKeyEventCallback())  
                this.callback.push(new UTSActivityCallback(), page.route)  
                this.callback.push(new UTSActivityComponentCallback())  
                this.callback.forEach((value) => {  
                    if (value instanceof UTSAcvitiyLifeCycleCallback) {  
                        UTSAndroid.onActivityCallback(value, page.route)  
                    }  
                    if (value instanceof UTSActivityWindowCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSAcvitiyKeyEventCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityComponentCallback) {  
                        UTSAndroid.onActivityCallback(value)  
                    }  

                })  
            },  
            unRegActivityCallback() {  
                this.callback.forEach((value) => {  

                    if (value instanceof UTSAcvitiyLifeCycleCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityWindowCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSAcvitiyKeyEventCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                    if (value instanceof UTSActivityComponentCallback) {  
                        UTSAndroid.offActivityCallback(value)  
                    }  
                })  
            }  
            // #endif  
            // #endif  
        },  
    }  
</script>

------uts代码------

代码位置:uni_modules/muts-syntaxcase/utssdk/app-android/index.uts

let callback : (eventLog : string) => void = (res) => { };  

export function onCallbackChange(fn : (eventLog : string) => void) {  
    callback = fn  
}  
import Bundle from "android.os.Bundle"  
import KeyEvent from "android.view.KeyEvent"  
import WindowManager from "android.view.WindowManager"   
import Menu from "android.view.Menu"  
import ActionMode from "android.view.ActionMode"  
import Configuration from "android.content.res.Configuration"  
import KeyboardShortcutGroup from "android.view.KeyboardShortcutGroup";  
export class UTSAcvitiyLifeCycleCallback extends UniActivityLifeCycleCallback {  
    constructor() {  
        super()  
    }  
    override onCreate(params : UniActivityParams, savedInstanceState : Bundle | null) {  
        console.log('UTSAcvitiyLifeCycle', 'onCreate', savedInstanceState)  
        callback('onCreate')  
    }  

    override onResume(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onResume', params)  
        callback('onResume')  
    }  
    override onPreResume(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onPreResume', params)  
        callback('onPreResume')  
    }  
    override onStart(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onStart', params)  
        callback('onStart')  
    }  
    override onPreStart(params : UniActivityParams) {  
        console.log('UTSAcvitiyLifeCycle', 'onPreStart', params)  
        callback('onPreStart')  
    }  
}  
export class UTSAcvitiyKeyEventCallback extends UniActivityKeyEventCallback {  
    constructor() {  
        super()  
    }  
    override onKeyDown(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onKeyDown', params, keyCode, '' + event)  
        callback('onKeyDown')  
    }  
    override onPreKeyDown(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onPreKeyDown', params, keyCode, '' + event)  
        callback('onPreKeyDown')  
    }  
    override onKeyLongPress(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onKeyLongPress', params, keyCode, '' + event)  
        callback('onKeyLongPress')  
    }  
    override onPreKeyLongPress(params : UniActivityParams, keyCode : Int, event : KeyEvent | null) {  
        console.log('UTSAcvitiyKeyEvent', 'onPreKeyLongPress', params, keyCode, '' + event)  
        callback('onPreKeyLongPress')  
    }  
}  

export class UTSActivityWindowCallback extends UniActivityWindowCallback {  
    constructor() {  
        super()  
    }  
    override dispatchPreKeyEvent(params : UniActivityParams, event : KeyEvent | null) {  
        console.log('UTSActivityWindowCallback', 'dispatchPreKeyEvent', params, '' + event)  
        callback('dispatchPreKeyEvent')  
    }  
    override dispatchKeyEvent(params : UniActivityParams, event : KeyEvent | null) {  
        console.log('UTSActivityWindowCallback', 'dispatchKeyEvent', params, '' + event)  
        callback('dispatchKeyEvent')  
    }  
    override  onWindowAttributesChanged(params : UniActivityParams, attrs : WindowManager.LayoutParams) {  
        console.log('UTSActivityWindowCallback', 'onWindowAttributesChanged', '' + attrs)  
        callback('onWindowAttributesChanged')  

    }  
    override onAttachedToWindow(params : UniActivityParams) {  
        console.log('UTSActivityWindowCallback', 'onAttachedToWindow', params)  
        callback('onAttachedToWindow')  

    }  
    override onPanelClosed(params : UniActivityParams, featureId : Int, menu : Menu) {  
        console.log('UTSActivityWindowCallback', 'onPanelClosed', featureId, menu)  
        callback('onPanelClosed')  

    }  
    override onWindowStartingActionMode(params : UniActivityParams, callback : ActionMode.Callback | null) {  
        console.log('UTSActivityWindowCallback', 'onWindowStartingActionMode', callback)  
        callback('onWindowStartingActionMode')  
    }  
    override onProvideKeyboardShortcuts(params : UniActivityParams, data : MutableList<KeyboardShortcutGroup> | null, menu : Menu | null, deviceId : Int) {  
        console.log('UTSActivityWindowCallback', 'onProvideKeyboardShortcuts', data, menu)  
        callback('onProvideKeyboardShortcuts')  
    }  
    override  onPreWindowAttributesChanged(params : UniActivityParams, attrs : WindowManager.LayoutParams) {  
        console.log('UTSActivityWindowCallback', 'onPreWindowAttributesChanged', attrs)  
        callback('onPreWindowAttributesChanged')  
    }  
    override  onPrePanelClosed(params : UniActivityParams, featureId : Int, menu : Menu) {  
        console.log('UTSActivityWindowCallback', 'onPrePanelClosed', featureId, menu)  
        callback('onPrePanelClosed')  
    }  
}  

export class UTSActivityCallback extends UniActivityCallback {  
    constructor() {  
        super()  
    }  
    override onRequestPermissionsResult(params : UniActivityParams, requestCode : Int, permissions : MutableList<String>, grantResults : IntArray) {  
        console.log('UTSActivityCallback', 'onRequestPermissionsResult', params)  
        callback('onRequestPermissionsResult')  
    }  

}  

export class UTSActivityComponentCallback extends UniActivityComponentCallback {  
    constructor() {  
        super()  
    }  
    override onConfigurationChanged(params : UniActivityParams, newConfig : Configuration) {  
        console.log('UTSActivityComponentCallback', 'onConfigurationChanged', params, '' + newConfig)  
        callback('onConfigurationChanged')  
    }  
    override onPreConfigurationChanged(params : UniActivityParams, newConfig : Configuration) {  
        console.log('UTSActivityComponentCallback', 'onPreConfigurationChanged', params, '' + newConfig)  
        callback('onPreConfigurationChanged')  
    }  
}

使用HbuilderX 4.74.2025063012-alpha版本编写

收起阅读 »

uniapp+vue3跨端小视频+直播+聊天模板【h5+小程序+app端】

vite vue3 uni-app

uniapp-vue3-welive:基于uni-app+vite5+vue3+uv-ui从0-1搭建实战跨平台仿抖音app实例。集成 短视频+聊天+直播 功能模块。支持编译到H5+小程序+App端、实现了全屏沉浸式滑动短视频/直播页面。支持拖拽自定义视频播放进度条。

项目知识点

  • 编辑器:HbuilderX 4.66
  • 框架技术:Uniapp+Vue3+Vite5+Nvue+Pinia2
  • UI组件库:uv-ui+vk-uview
  • 弹框组件:uaPopup(uniapp封装多端弹框组件)
  • 自定义组件:uaNavbar+uaTabbar组件
  • 本地缓存:pinia-plugin-unistorage
  • 编译支持:h5+小程序+APP端

项目框架结构目录

使用uni-app+vite5搭建项目模板,采用vue3 setup语法编码。

目前uni-vue3-douyin项目已经发布到我的原创作品小铺。
uni-app+vue3+pinia2+uv-ui跨三端短视频+聊天+直播商城

热文推荐

原创uniapp+vue3+deepseek+uv-ui跨端实战仿deepseek/豆包流式ai聊天对话助手。
vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果
Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
uniapp+vue3酒店预订|vite5+uniapp预约订房系统模板(h5+小程序+App端)
tauri2.0-admin桌面端后台系统|Tauri2+Vite5+ElementPlus管理后台EXE程序
Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天应用
Electron32-Vue3OS桌面版os系统|vue3+electron+arco客户端OS管理模板

继续阅读 »

uniapp-vue3-welive:基于uni-app+vite5+vue3+uv-ui从0-1搭建实战跨平台仿抖音app实例。集成 短视频+聊天+直播 功能模块。支持编译到H5+小程序+App端、实现了全屏沉浸式滑动短视频/直播页面。支持拖拽自定义视频播放进度条。

项目知识点

  • 编辑器:HbuilderX 4.66
  • 框架技术:Uniapp+Vue3+Vite5+Nvue+Pinia2
  • UI组件库:uv-ui+vk-uview
  • 弹框组件:uaPopup(uniapp封装多端弹框组件)
  • 自定义组件:uaNavbar+uaTabbar组件
  • 本地缓存:pinia-plugin-unistorage
  • 编译支持:h5+小程序+APP端

项目框架结构目录

使用uni-app+vite5搭建项目模板,采用vue3 setup语法编码。

目前uni-vue3-douyin项目已经发布到我的原创作品小铺。
uni-app+vue3+pinia2+uv-ui跨三端短视频+聊天+直播商城

热文推荐

原创uniapp+vue3+deepseek+uv-ui跨端实战仿deepseek/豆包流式ai聊天对话助手。
vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果
Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
uniapp+vue3酒店预订|vite5+uniapp预约订房系统模板(h5+小程序+App端)
tauri2.0-admin桌面端后台系统|Tauri2+Vite5+ElementPlus管理后台EXE程序
Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天应用
Electron32-Vue3OS桌面版os系统|vue3+electron+arco客户端OS管理模板

收起阅读 »

iOS APP性能调试、优化实战:跨国性能与兼容性保障的全流程方法

iOS

'''当iOS App走向海外,从单一国家到多地区发布,常常会遇到与国内项目完全不同的挑战:
1.各地网络环境差异巨大,影响接口响应和页面加载
2.设备型号分布不同,比如海外低配iPhone普及率更高
3.不同语言和地区格式导致UI排版、数据展示异常
4.远程调试受限,无法像本地一样随时连接真机排查
这些问题如果不解决,会让海外用户体验急剧下滑,导致留存率骤降。

我参与过多个面向欧美、东南亚、非洲市场的出海项目,踩过不少坑。今天分享一套我们在跨国项目中使用的工具组合和流程,让你即使和海外设备隔着万里,也能系统地收集问题并分析原因。


01|多地区网络环境的接口稳定性调试

国内的接口在局域网或CDN加速下表现完美,但到了海外后,网络延迟、丢包会直接引发卡顿、接口超时或逻辑错误。

工具组合:

  • Charles / Proxyman:本地代理模拟弱网、丢包,观察App请求在高延迟环境下表现。
  • 克魔性能面板:记录真实海外设备上的网络请求耗时、失败率。

> 实战:在测试非洲市场时,通过克魔抓到接口平均响应延迟达到3秒以上,并通过Charles做弱网模拟优化了接口重试逻辑,App白屏时间从6秒降到2秒。


02|设备兼容性:低配iPhone和老系统的真机验证

很多海外地区主力机型仍是iPhone 6/7/SE,性能瓶颈与iOS 15及以下系统特性差异会引发独特问题,例如动画掉帧、系统API兼容性崩溃等。

工具组合:

  • 克魔性能监测:低端设备上FPS、CPU、内存走势的长期记录。
  • Instruments:国内环境可用时做函数级别性能分析。

> 实战:在老iPhone SE上通过克魔发现Banner自动轮播时FPS波动剧烈,最终用分页懒加载代替一次性图片下载解决问题。


03|远程语言环境下的UI布局兼容性

多语言常常带来UI错位、文本溢出,尤其在阿拉伯语等右到左语言、德语等超长单词中尤为突出。

工具组合:

  • 克魔文件管理:在海外测试设备上拉取配置文件、截图,确认国际化资源加载是否符合语言环境。
  • Xcode Previews:模拟不同语言,但真机仍需配合克魔远程验证。

> 实战:在阿联酋本地化中,通过克魔查看沙盒中语言配置文件,发现系统未正确写入ar-AE导致App强制回退英文,修复后保证UI布局按RTL方向排版。


04|崩溃与异常的远程追踪与符号化

海外用户遇到崩溃时,你往往拿不到真机也无法复现,这时候能否快速拿到崩溃日志、做符号化还原就决定了问题修复效率。

工具组合:

  • 克魔崩溃日志模块:导出.crash文件发送回国
  • symbolicatecrash:本地结合dSYM文件做符号化

> 实战:在泰国市场上线后出现30%概率闪退,通过当地测试用克魔导出崩溃日志并符号化,锁定是一个CoreLocation回调未处理nil导致,最终通过条件判断修复。


05|海外用户行为追踪与能耗分析

在一些网络和电力条件较差的国家,App如果后台耗电高,用户很快会卸载,因此需要定期查看海外设备上App使用记录和资源消耗。

工具组合:

  • 克魔使用记录:最长6个月的App使用、CPU、网络、GPU等耗电统计
  • 系统设置电池使用:和克魔数据对比验证一致性

> 实战:印尼市场用户反馈夜间待机电量异常,通过克魔使用记录确认App在后台被唤醒后长时间保持网络连接,最终用后台任务超时强制关闭解决。


06|分布式团队跨国调试协作流程

跨国项目中,研发、测试、运营往往跨越几个时区,要让调试数据流转顺畅,我们会使用以下流程:

  1. 海外测试同事通过克魔执行全流程用例,记录性能趋势并导出崩溃、日志、文件结构。
  2. 上传到统一共享盘或企业IM群,自动触发Jenkins脚本将文件打标签归档。
  3. 国内研发用symbolicatecrash符号化崩溃,结合性能曲线进行对照分析。
  4. 每周例会集中汇总不同地区问题,按国家/语言/设备类型维度跟踪。

07|跨国调试工具组合清单

调试需求 工具组合
网络稳定性 Charles弱网模拟 + 克魔远程网络监控
性能分析 克魔FPS/CPU/GPU趋势 + Instruments
UI多语言适配 克魔文件/截图验证 + Xcode Previews
崩溃定位 克魔崩溃日志 + symbolicatecrash
行为与能耗分析 克魔使用记录 + 系统设置电池页面

结语:做跨国App,调试和体验验证要全球化

如果只依赖本地环境,出海项目永远无法感知真实海外用户的使用环境差异。构建一套能在全球范围内拉取真机数据、验证性能、收集崩溃的流程,是保障跨国App体验一致性的关键。'''

继续阅读 »

'''当iOS App走向海外,从单一国家到多地区发布,常常会遇到与国内项目完全不同的挑战:
1.各地网络环境差异巨大,影响接口响应和页面加载
2.设备型号分布不同,比如海外低配iPhone普及率更高
3.不同语言和地区格式导致UI排版、数据展示异常
4.远程调试受限,无法像本地一样随时连接真机排查
这些问题如果不解决,会让海外用户体验急剧下滑,导致留存率骤降。

我参与过多个面向欧美、东南亚、非洲市场的出海项目,踩过不少坑。今天分享一套我们在跨国项目中使用的工具组合和流程,让你即使和海外设备隔着万里,也能系统地收集问题并分析原因。


01|多地区网络环境的接口稳定性调试

国内的接口在局域网或CDN加速下表现完美,但到了海外后,网络延迟、丢包会直接引发卡顿、接口超时或逻辑错误。

工具组合:

  • Charles / Proxyman:本地代理模拟弱网、丢包,观察App请求在高延迟环境下表现。
  • 克魔性能面板:记录真实海外设备上的网络请求耗时、失败率。

> 实战:在测试非洲市场时,通过克魔抓到接口平均响应延迟达到3秒以上,并通过Charles做弱网模拟优化了接口重试逻辑,App白屏时间从6秒降到2秒。


02|设备兼容性:低配iPhone和老系统的真机验证

很多海外地区主力机型仍是iPhone 6/7/SE,性能瓶颈与iOS 15及以下系统特性差异会引发独特问题,例如动画掉帧、系统API兼容性崩溃等。

工具组合:

  • 克魔性能监测:低端设备上FPS、CPU、内存走势的长期记录。
  • Instruments:国内环境可用时做函数级别性能分析。

> 实战:在老iPhone SE上通过克魔发现Banner自动轮播时FPS波动剧烈,最终用分页懒加载代替一次性图片下载解决问题。


03|远程语言环境下的UI布局兼容性

多语言常常带来UI错位、文本溢出,尤其在阿拉伯语等右到左语言、德语等超长单词中尤为突出。

工具组合:

  • 克魔文件管理:在海外测试设备上拉取配置文件、截图,确认国际化资源加载是否符合语言环境。
  • Xcode Previews:模拟不同语言,但真机仍需配合克魔远程验证。

> 实战:在阿联酋本地化中,通过克魔查看沙盒中语言配置文件,发现系统未正确写入ar-AE导致App强制回退英文,修复后保证UI布局按RTL方向排版。


04|崩溃与异常的远程追踪与符号化

海外用户遇到崩溃时,你往往拿不到真机也无法复现,这时候能否快速拿到崩溃日志、做符号化还原就决定了问题修复效率。

工具组合:

  • 克魔崩溃日志模块:导出.crash文件发送回国
  • symbolicatecrash:本地结合dSYM文件做符号化

> 实战:在泰国市场上线后出现30%概率闪退,通过当地测试用克魔导出崩溃日志并符号化,锁定是一个CoreLocation回调未处理nil导致,最终通过条件判断修复。


05|海外用户行为追踪与能耗分析

在一些网络和电力条件较差的国家,App如果后台耗电高,用户很快会卸载,因此需要定期查看海外设备上App使用记录和资源消耗。

工具组合:

  • 克魔使用记录:最长6个月的App使用、CPU、网络、GPU等耗电统计
  • 系统设置电池使用:和克魔数据对比验证一致性

> 实战:印尼市场用户反馈夜间待机电量异常,通过克魔使用记录确认App在后台被唤醒后长时间保持网络连接,最终用后台任务超时强制关闭解决。


06|分布式团队跨国调试协作流程

跨国项目中,研发、测试、运营往往跨越几个时区,要让调试数据流转顺畅,我们会使用以下流程:

  1. 海外测试同事通过克魔执行全流程用例,记录性能趋势并导出崩溃、日志、文件结构。
  2. 上传到统一共享盘或企业IM群,自动触发Jenkins脚本将文件打标签归档。
  3. 国内研发用symbolicatecrash符号化崩溃,结合性能曲线进行对照分析。
  4. 每周例会集中汇总不同地区问题,按国家/语言/设备类型维度跟踪。

07|跨国调试工具组合清单

调试需求 工具组合
网络稳定性 Charles弱网模拟 + 克魔远程网络监控
性能分析 克魔FPS/CPU/GPU趋势 + Instruments
UI多语言适配 克魔文件/截图验证 + Xcode Previews
崩溃定位 克魔崩溃日志 + symbolicatecrash
行为与能耗分析 克魔使用记录 + 系统设置电池页面

结语:做跨国App,调试和体验验证要全球化

如果只依赖本地环境,出海项目永远无法感知真实海外用户的使用环境差异。构建一套能在全球范围内拉取真机数据、验证性能、收集崩溃的流程,是保障跨国App体验一致性的关键。'''

收起阅读 »