HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

经验分享 鸿蒙里的权限设置,如何获取、查询权限

鸿蒙next

鸿蒙里的权限

鸿蒙的权限可以分成三类:

开放权限:system_grant, 比如 INTERNET网络权限、VIBRATE 手机震动权限等。无需用户同意。具体可见 开放权限(系统授权)
用户授权:user_grant,弹窗询问用户是否允许位置定位、发送通知等。具体可见 开放权限(用户授权)
敏感权限:需要在华为后台单独填写表格申请获得,比如修改用户公共目录文件、API 读取剪切板等。具体可见 受限开放权限
还有一些针对特定企业管理的权限,场景比较特殊,这里不做进一步描述。

细节可以看文档 《鸿蒙权限配置指南

如何定义权限

举例定位中用到的模糊定位、精准定位。需要参考文档,在 requestPermissions

如何查询权限是否授权?

const auth = () => {  
    const res = uni.getAppAuthorizeSetting()  
    console.log(res)  
  }

如何主动申请用户授权特定的权限?

先见 uts-api 鸿蒙插件,填写下面代码, uni_modules/harmony-harmony/utssdk/app-harmony/index.uts

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';  

export const requestSystemPermission = () => {  

  const permissionList : Array<Permissions> = ['ohos.permission.APPROXIMATELY_LOCATION']  
  UTSHarmony.requestSystemPermission(permissionList, (allRight : boolean, grantedList : Array<string>) => {  
    console.log('res', allRight, grantedList);  
  }, (doNotAskAgain : boolean, grantedList : Array<string>) => {  
    console.log('fail', doNotAskAgain, grantedList);  
  })  
}

在 vue 代码中这样使用

<script setup lang="uts">  
  import { requestSystemPermission } from '@/uni_modules/harmony-harmony'  

  const permisson = () => {  
    requestSystemPermission()  
  }  
</script>

如何打开系统设置?

可引导用户打开设置重新授权。

uni.openAppAuthorizeSetting()  

https://uniapp.dcloud.net.cn/api/system/openappauthorizesetting.html

继续阅读 »

鸿蒙里的权限

鸿蒙的权限可以分成三类:

开放权限:system_grant, 比如 INTERNET网络权限、VIBRATE 手机震动权限等。无需用户同意。具体可见 开放权限(系统授权)
用户授权:user_grant,弹窗询问用户是否允许位置定位、发送通知等。具体可见 开放权限(用户授权)
敏感权限:需要在华为后台单独填写表格申请获得,比如修改用户公共目录文件、API 读取剪切板等。具体可见 受限开放权限
还有一些针对特定企业管理的权限,场景比较特殊,这里不做进一步描述。

细节可以看文档 《鸿蒙权限配置指南

如何定义权限

举例定位中用到的模糊定位、精准定位。需要参考文档,在 requestPermissions

如何查询权限是否授权?

const auth = () => {  
    const res = uni.getAppAuthorizeSetting()  
    console.log(res)  
  }

如何主动申请用户授权特定的权限?

先见 uts-api 鸿蒙插件,填写下面代码, uni_modules/harmony-harmony/utssdk/app-harmony/index.uts

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';  

export const requestSystemPermission = () => {  

  const permissionList : Array<Permissions> = ['ohos.permission.APPROXIMATELY_LOCATION']  
  UTSHarmony.requestSystemPermission(permissionList, (allRight : boolean, grantedList : Array<string>) => {  
    console.log('res', allRight, grantedList);  
  }, (doNotAskAgain : boolean, grantedList : Array<string>) => {  
    console.log('fail', doNotAskAgain, grantedList);  
  })  
}

在 vue 代码中这样使用

<script setup lang="uts">  
  import { requestSystemPermission } from '@/uni_modules/harmony-harmony'  

  const permisson = () => {  
    requestSystemPermission()  
  }  
</script>

如何打开系统设置?

可引导用户打开设置重新授权。

uni.openAppAuthorizeSetting()  

https://uniapp.dcloud.net.cn/api/system/openappauthorizesetting.html

收起阅读 »

经验分享 鸿蒙通过 WebView 打开页面渲染成桌面 pc 模式怎么办?

鸿蒙next

鸿蒙开发时候可使用 WebView 组件加载网页,展示网页内容并通信。

历史改动

在 HBuilderX 4.81 之后, uniapp 使用 WebView 展示在线网页时候,会默认添加 metaViwe=true,读取并启用 meta viewport 字段。

userAgent 适配

还有一部分网页是读取的 useragent 属性,通过特征判断再渲染展示网页,有的 isMobile 的判断里缺少鸿蒙的判断,只判断了 iphone/ipad/android 等字段,没有判断 OpenHarmony AkWeb 字段,如果是这种响应式展示移动端的方案,一方面可以更新 isMobile 的判断,添加对 harmony 的解析。另一方面可以在 HBuilderX 的 mainfest.json 中主动设置 UserAgent 来规避这个问题。

按照下面操作步骤:
打开 mianfest.json 切换到源码模式,找到 app-harmony 字段,追加下面字段

{"useragent":{"value":"Android","concatenate" : true}}

这下面在系统默认的 UserAgent 之后追加 Android 字段,通过这种方式主动适配网页。

uniapp 默认的 userAgent

Mozilla/5.0 (Phone; OpenHarmony 5.1)  
AppleWebKit/537.36 (KHTML, like Gecko)  
Chrome/114.0.0.0 Safari/537.36 ArkWeb/5.1.0.211  
Mobile uni-app
继续阅读 »

鸿蒙开发时候可使用 WebView 组件加载网页,展示网页内容并通信。

历史改动

在 HBuilderX 4.81 之后, uniapp 使用 WebView 展示在线网页时候,会默认添加 metaViwe=true,读取并启用 meta viewport 字段。

userAgent 适配

还有一部分网页是读取的 useragent 属性,通过特征判断再渲染展示网页,有的 isMobile 的判断里缺少鸿蒙的判断,只判断了 iphone/ipad/android 等字段,没有判断 OpenHarmony AkWeb 字段,如果是这种响应式展示移动端的方案,一方面可以更新 isMobile 的判断,添加对 harmony 的解析。另一方面可以在 HBuilderX 的 mainfest.json 中主动设置 UserAgent 来规避这个问题。

按照下面操作步骤:
打开 mianfest.json 切换到源码模式,找到 app-harmony 字段,追加下面字段

{"useragent":{"value":"Android","concatenate" : true}}

这下面在系统默认的 UserAgent 之后追加 Android 字段,通过这种方式主动适配网页。

uniapp 默认的 userAgent

Mozilla/5.0 (Phone; OpenHarmony 5.1)  
AppleWebKit/537.36 (KHTML, like Gecko)  
Chrome/114.0.0.0 Safari/537.36 ArkWeb/5.1.0.211  
Mobile uni-app
收起阅读 »

避坑指南,鸿蒙APP备案获取公钥和证书指纹MD5的方法

app备案

开发好鸿蒙APP,在鸿蒙APP备案的时候,获取公钥和MD5是通过发布证书.cer文件来获取公钥的。

而华为的.cer文件,使用记事本打开,里面的证书有三段,其中两段是根证书和中间证书,是需要删除的,假如不删除获取到的公钥和MD5是不对的。

但是问题是,里面文件的有好几段证书内容,不熟悉的同学看不出来哪一段是根证书,哪一段中间证书。容易删除

而且假如是mac电脑或linux电脑,删除后的cer文件,阿里云官方也不知道如何查看16进制的公钥和MD5信息。

所以这里,我建议是使用香蕉云编在线查看公钥,就不怕查错了:

https://www.yunedit.com/harmonymd5

如下图所示:

点击查询后,如下图,出现的16进制公钥就是要备案的公钥了

继续阅读 »

开发好鸿蒙APP,在鸿蒙APP备案的时候,获取公钥和MD5是通过发布证书.cer文件来获取公钥的。

而华为的.cer文件,使用记事本打开,里面的证书有三段,其中两段是根证书和中间证书,是需要删除的,假如不删除获取到的公钥和MD5是不对的。

但是问题是,里面文件的有好几段证书内容,不熟悉的同学看不出来哪一段是根证书,哪一段中间证书。容易删除

而且假如是mac电脑或linux电脑,删除后的cer文件,阿里云官方也不知道如何查看16进制的公钥和MD5信息。

所以这里,我建议是使用香蕉云编在线查看公钥,就不怕查错了:

https://www.yunedit.com/harmonymd5

如下图所示:

点击查询后,如下图,出现的16进制公钥就是要备案的公钥了

收起阅读 »

经验分享 鸿蒙中如何隐藏底部触控小白条?

鸿蒙next

在鸿蒙底部有触控小白条,用来响应系统级用户手势。在应用开发时候,有些业务场景需要隐藏底部触控小白条,鸿蒙提供了响应 API,代码比较简单,使用 UTS 几行代码轻松切换展示。

在 HBuilderX 中新建 uni_modules 文件夹,在 uni_modules 文件夹右键选择创建 UTS-API 插件,创建并编辑 app-harmony/index.uts 文件夹,如果没有就新建该文件。

在文件中填写下面代码:


/**  
 * 展示底部小白条  
 */  
export const showNavigationIndicator = () => {  
  const window = UTSHarmony.getCurrentWindow()  
  window.setSpecificSystemBarEnabled('navigationIndicator', true)  
}  

/**  
 * 隐藏底部小白条  
 */  
export const hideNavigationIndicator = () => {  
  const window = UTSHarmony.getCurrentWindow()  
  window.setSpecificSystemBarEnabled('navigationIndicator', false)  
}  

在 Vue 页面中导入并使用即可。

<template>  
  <view>  
    <button @click="showNavigationIndicator">showNavigationIndicator</button>  
    <button @click="hideNavigationIndicator">hideNavigationIndicator</button>  
  </view>  
</template>  
<script setup lang="uts">  
  import {  
    showNavigationIndicator,  
    hideNavigationIndicator,  
  } from '@/uni_modules/harmony-toggle-navigation-indicator'  
</script>  

当用户点击 hideNavigationIndicator 按钮之后,系统大概一秒后会隐藏小白条。点击 showNavigationIndicator 系统会展示小白条。

继续阅读 »

在鸿蒙底部有触控小白条,用来响应系统级用户手势。在应用开发时候,有些业务场景需要隐藏底部触控小白条,鸿蒙提供了响应 API,代码比较简单,使用 UTS 几行代码轻松切换展示。

在 HBuilderX 中新建 uni_modules 文件夹,在 uni_modules 文件夹右键选择创建 UTS-API 插件,创建并编辑 app-harmony/index.uts 文件夹,如果没有就新建该文件。

在文件中填写下面代码:


/**  
 * 展示底部小白条  
 */  
export const showNavigationIndicator = () => {  
  const window = UTSHarmony.getCurrentWindow()  
  window.setSpecificSystemBarEnabled('navigationIndicator', true)  
}  

/**  
 * 隐藏底部小白条  
 */  
export const hideNavigationIndicator = () => {  
  const window = UTSHarmony.getCurrentWindow()  
  window.setSpecificSystemBarEnabled('navigationIndicator', false)  
}  

在 Vue 页面中导入并使用即可。

<template>  
  <view>  
    <button @click="showNavigationIndicator">showNavigationIndicator</button>  
    <button @click="hideNavigationIndicator">hideNavigationIndicator</button>  
  </view>  
</template>  
<script setup lang="uts">  
  import {  
    showNavigationIndicator,  
    hideNavigationIndicator,  
  } from '@/uni_modules/harmony-toggle-navigation-indicator'  
</script>  

当用户点击 hideNavigationIndicator 按钮之后,系统大概一秒后会隐藏小白条。点击 showNavigationIndicator 系统会展示小白条。

收起阅读 »

经验分享 如何在鸿蒙应用中唤起鸿蒙应用、元服务

鸿蒙next

鸿蒙应用如何注册和声明 DeepLink 和 AppLinking 可参考 《通过 URL Scheme 唤起鸿蒙应用

这里重点介绍如何在应用中唤起其他应用和元服务。

鸿蒙唤起鸿蒙、元服务已经迁移到文档 《鸿蒙应用唤起鸿蒙应用、元服务

鸿蒙元服务唤起鸿蒙应用已经迁移到文档 《鸿蒙元服务唤起鸿蒙应用

继续阅读 »

鸿蒙应用如何注册和声明 DeepLink 和 AppLinking 可参考 《通过 URL Scheme 唤起鸿蒙应用

这里重点介绍如何在应用中唤起其他应用和元服务。

鸿蒙唤起鸿蒙、元服务已经迁移到文档 《鸿蒙应用唤起鸿蒙应用、元服务

鸿蒙元服务唤起鸿蒙应用已经迁移到文档 《鸿蒙元服务唤起鸿蒙应用

收起阅读 »

一键登录获取华为账号绑定号码不返回

一键登录 鸿蒙next

原因可能是 请求Authorization Code时无法携带quickLoginMobilePhone scope

<template>  
  <view>  
    <button @click="getProviderSync">getProviderSync</button>  
    <button @click="login">login</button>  
    <button @click="getUserInfo">getUserInfo</button>  
  </view>  
</template>  
<script setup>  
const getProviderSync = () => {  
  const provider = uni.getProviderSync({service: 'oauth'})  
  console.log('provider :>> ' + JSON.stringify(provider));  
}  

const login = () => {  
  uni.login({  
    provider: 'huawei',  
    success(res) {  
      console.log(JSON.stringify(res))  
    },  
    fail(err) {  
      console.log(JSON.stringify(err))  
    },  
  })  
}  

const getUserInfo = () => {  
  uni.getUserInfo({  
    provider: 'huawei',  
    success(res) {  
      console.log(JSON.stringify(res))  
    },  
    fail(err) {  
      console.log(JSON.stringify(err))  
    },  
  })  
}  
</script>  
继续阅读 »

原因可能是 请求Authorization Code时无法携带quickLoginMobilePhone scope

<template>  
  <view>  
    <button @click="getProviderSync">getProviderSync</button>  
    <button @click="login">login</button>  
    <button @click="getUserInfo">getUserInfo</button>  
  </view>  
</template>  
<script setup>  
const getProviderSync = () => {  
  const provider = uni.getProviderSync({service: 'oauth'})  
  console.log('provider :>> ' + JSON.stringify(provider));  
}  

const login = () => {  
  uni.login({  
    provider: 'huawei',  
    success(res) {  
      console.log(JSON.stringify(res))  
    },  
    fail(err) {  
      console.log(JSON.stringify(err))  
    },  
  })  
}  

const getUserInfo = () => {  
  uni.getUserInfo({  
    provider: 'huawei',  
    success(res) {  
      console.log(JSON.stringify(res))  
    },  
    fail(err) {  
      console.log(JSON.stringify(err))  
    },  
  })  
}  
</script>  
收起阅读 »

鸿蒙企业应用内部分发打包教程

分发 鸿蒙next

使用 HBuilderX 开发 uni-app (x) 应用,可以很容易地构建出一款鸿蒙应用。

多数开发者都是要通过华为的应用商店来发布自己的应用,但是也有开发者是为企业开发的内部应用,在这个场景下,只需要把应用的安装包分发给特定的少数用户就可以了。

华为的应用商店也支持这个场景,即非公开发布:开发者可以将不适合公开分发的应用以非公开方式在华为应用市场上发布,使其仅可通过链接被用户发现。

不过,对于开发者而言,要发布这样的应用有一定的资质要求,每次发版的时候也是要走流程,要接受审核,好处就是可以享受华为应用商店的分发服务。

所以,有些开发者希望能绕过这个发布流程,通过自有的下载服务直接向使用者提供安装包,即:内部分发

HBuilderX 的开发流程是可以支持内部分发模式的,只不过有些环节需要手动操作来配合。

本文假设读者已经熟悉了 HBuilderX 开发鸿蒙应用的基本操作,下面我们就一步一步来看怎么实现应用的内部分发。

先说一下内部分发的局限性:

  • 要有自己的下载服务,可以是自建的 Web Server,也可以是购买的云服务。

  • 内部分发的目标用户是事先确定的(要先采集到他们的设备唯一标识),每个安装包可以分发给最多 100 个设备。

要实现内部分发,需要以下几个步骤:

一. 准备数字签名相关资料。

二. 用 HBuilderX 以【运行到鸿蒙】的方式得到 .hap 安装包。

三. 编写内部分发所需要的相关文件,并上传到服务器供用户下载。

下面详细说明每个步骤。我将使用 DCloud 官方提供的开源项目 hello-uni-app-x 来演示操作。

一. 准备数字签名相关资料

在 HBuilderX 里面打开项目的 manifest.json 文件,进入【鸿蒙App配置】,点击调试证书那个【配置】按钮。

弹出了【配置调试证书】的对话框:

能看到这里有个【自动申请调试证书】的按钮,但是,不要点击它!
因为用调试证书签名的安装包只能使用 hdc 命令安装到开启了开发者选项的手机上,这不是我们想要的。

我们需要自己到 AppGallery Connect 网站上手动申请用于内部测试的证书文件,然后再填写到这个对话框里。

注意上面的对话框里面有个【运行设备-检测】按钮,只要把开启了开发者选项的手机连接到电脑上,点击这个按钮就可以采集到设备标识。

完整的手动申请证书的操作可以看鸿蒙的官方文档,我这里只简要介绍一下步骤:

这一步需要留意的是你使用的应用包名。

所有需要参与内部分发的手机都要先采集到设备标识,并 提交到 AppGallery Connect,后续申请 profile 文件时需要它们。

这一步你将得到一个私钥库文件(.p12)和一个证书申请文件(.csr)。
请记住你使用的密码,有两个(一个是访问私钥库的密码,另一个是访问私钥的密码,但一般都使用相同的密码)。
也请记住你使用的私钥别名,这些在最后填写【配置调试证书】的时候都会用到。

这一步需要上传 .csr 文件,你将得到一个发布证书文件(.cer),下载到本地备用。

这一步你将得到一个 profile 文件(.p7b),下载到本地备用。
【类型】请选择【内部测试】,【证书】就选择上一步得到的发布证书,【设备】请选上所有需要参与内部分发的手机,你应该已经把它们都提交过了。

做完上面这几步,你就可以回到 HBuilderX 中,打开【配置调试证书】对话框,把所有的内容都填好并保存。
【运行设备】那里只要有当前连接的设备就好了,对于最后生成的 .hap 没有影响。

二. 用 HBuilderX 以【运行到鸿蒙】的方式得到 .hap 安装包

在 HBuilderX 里面点击菜单项【运行>运行到手机或模拟器>运行到鸿蒙】,弹出运行对话框,选择好运行设备,点击【运行】按钮。

正常来说,应用就可以在手机上运行起来了,而你在 HBuilderX 控制台里面可以看到下面这些内容:

红框里的目录就是用于构建鸿蒙运行包的鸿蒙工程目录,在里面能够找到已签名的运行包:

对于内部分发而言,这个运行包就是所需要的安装包了,你可以把它改成一个更合适的名字(比如 my-internal-app.hap)备用。

请记住这个 app-harmony 目录,下一步有些需要的东西得在这个目录里找。

三. 编写内部分发所需要的相关文件,并上传到服务器供用户下载

这里假定你的服务器域名为 www.my-server.com

1. 先上传两个文件,并得到下载链接。

把前面得到的安装包(.hap)上传到你的服务器,得到对应的下载链接,比如 https://www.my-server.com/my-internal-app.hap

再准备两个图片文件,作为下载安装过程中显示的图标。按照鸿蒙官方文档的说法,需要准备一大一小两个图标,但我没有找到关于具体规格的说明,索性就直接用 app-harmony/AppScope/resources/base/media/foreground.png 这个文件把两者都代替了。
上传后也是得到了下载链接,比如 https://www.my-server.com/foreground.png

2. 编写一个内部分发描述文件 manifest.json5

须按照 鸿蒙官方文档 的指导编写这个文件。

由于这个文件编写好之后还需要进行签名,所以我们暂且保存为文件名 manifest-unsigned.json5,签名后将得到 manifest.json5

其中有几个属性值可以从 app-harmony/AppScope/app.json5 文件里找到:

  • bundleName
  • versionCode
  • versionName

还有几个属性需要特别说明一下:

  • minAPIVersiontargetAPIVersion

app-harmony/build-profile.json5 文件中找到 app.products 数组,在里面找到 compatibleSdkVersion 值(可能有多个,但应该是相同的值),把 minAPIVersiontargetAPIVersion 都填成这个值就行了。

  • deployDomain

这个是将来用于提供下载服务的域名,填写你自己实际的服务域名即可,比如前面说的 www.my-server.com

  • icons 里面的 normallarge

这里填写的是将来下载时显示的图标的网址,就填写前面上传图标文件得到的链接地址。

  • modules

此项看上去比较复杂,需要参照 app-harmony/build-profile.json5 文件中的 modules 来改写,每个打包出来的独立模块都要在这里填写。

但实际上,多数情况下构建产物里只会有一个模块,就是主模块(该模块的 nametype 都是 entry),也就是前面提到的 .hap 文件。

  • modules 里面的 packageUrlpackageHash

这里的 package 指的就是前面得到的安装包 .hap 文件,packageUrl 填写的是将来下载安装包时使用的网址,packageHash 填写的是这个安装包文件的 SHA256 哈希值。

  • sign

这一项是对这个描述文件本身的签名,无需手动填写,下一步将使用签名工具来生成它。

写好的 manifest-unsigned.json5 文件大体上会是下面这个样子:

{  
  "app": {  
    "bundleName": "io.dcloud.uniappx",  
    "bundleType": "app",  
    "versionCode": 10907,  
    "versionName": "1.9.7",  
    "label": "Hello uni-app x",  
    "deployDomain": "www.my-server.com",  
    "icons": {  
      "normal": "https://www.my-server.com/foreground.png",  
      "large": "https://www.my-server.com/foreground.png"  
    },  
    "minAPIVersion": "5.0.1(13)",  
    "targetAPIVersion": "5.0.1(13)",  
    "modules": [  
      {  
        "name": "entry",  
        "type": "entry",  
        "deviceTypes": ["phone", "tablet", "2in1"],  
        "packageUrl": "https://www.my-server.com/my-internal-app.hap",  
        "packageHash": "27005caa60761b863fbf0fbcd0f96159386de038f59102f0ec676532cd49b084"  
      }  
    ]  
  }  
}

3. 对描述文件 manifest.json5 做签名并上传。

先下载 签名工具,注意其中的 manifest-sign-tool-1.0.0.jar,用 java 执行它:

java -jar "<manifest-sign-tool-1.0.0.jar的绝对路径>" \  
-operation sign \  
-mode localjks \  
-inputFile "<前面编写的manifest-unsigned.json5文件的绝对路径>" \  
-outputFile "<将要生成的manifest.json5文件的绝对路径>" \  
-keystore "<私钥库.p12文件的绝对路径>" \  
-keystorepasswd <私钥库密码> \  
-keyaliaspasswd <私钥密码> \  
-privatekey <私钥别名>

这样就会得到包含签名的 manifest.json 文件,上传到服务器,得到对应的下载链接,比如 https://www.my-server.com/manifest.json5

4. 编写一个网页文件并上传。

编写一个 index.html 文件,内容如下:

<!DOCTYPE html>  
<html lang="zh-CN">  
  <head>  
    <meta charset="UTF-8"/>  
    <meta name="viewport" content="width=device-width, initial-scale=1"/>  
    <title>企业内部分发</title>  
    <script>  
      function openDeepLink() {  
        let url ='store://enterprise/manifest?url=https://www.my-server.com/manifest.json5'  
        window.open(url, '_parent')  
      }  
    </script>  
  </head>  
  <body>  
    <button onclick="openDeepLink()">下载安装</button>  
  </body>  
</html>

注意里面的下载链接,要替换成你自己实际的链接地址。

index.html 文件上传到服务器,得到对应的下载链接,比如 https://www.my-server.com/index.html

好了,大功告成!

下面只要告诉参与内部分发的用户,用手机里面的鸿蒙官方浏览器打开这个网址,就可以点击其中的按钮下载安装了。

你也可以把这个网址做成二维码,让用户使用手机的浏览器扫码访问,这样会更方便。

继续阅读 »

使用 HBuilderX 开发 uni-app (x) 应用,可以很容易地构建出一款鸿蒙应用。

多数开发者都是要通过华为的应用商店来发布自己的应用,但是也有开发者是为企业开发的内部应用,在这个场景下,只需要把应用的安装包分发给特定的少数用户就可以了。

华为的应用商店也支持这个场景,即非公开发布:开发者可以将不适合公开分发的应用以非公开方式在华为应用市场上发布,使其仅可通过链接被用户发现。

不过,对于开发者而言,要发布这样的应用有一定的资质要求,每次发版的时候也是要走流程,要接受审核,好处就是可以享受华为应用商店的分发服务。

所以,有些开发者希望能绕过这个发布流程,通过自有的下载服务直接向使用者提供安装包,即:内部分发

HBuilderX 的开发流程是可以支持内部分发模式的,只不过有些环节需要手动操作来配合。

本文假设读者已经熟悉了 HBuilderX 开发鸿蒙应用的基本操作,下面我们就一步一步来看怎么实现应用的内部分发。

先说一下内部分发的局限性:

  • 要有自己的下载服务,可以是自建的 Web Server,也可以是购买的云服务。

  • 内部分发的目标用户是事先确定的(要先采集到他们的设备唯一标识),每个安装包可以分发给最多 100 个设备。

要实现内部分发,需要以下几个步骤:

一. 准备数字签名相关资料。

二. 用 HBuilderX 以【运行到鸿蒙】的方式得到 .hap 安装包。

三. 编写内部分发所需要的相关文件,并上传到服务器供用户下载。

下面详细说明每个步骤。我将使用 DCloud 官方提供的开源项目 hello-uni-app-x 来演示操作。

一. 准备数字签名相关资料

在 HBuilderX 里面打开项目的 manifest.json 文件,进入【鸿蒙App配置】,点击调试证书那个【配置】按钮。

弹出了【配置调试证书】的对话框:

能看到这里有个【自动申请调试证书】的按钮,但是,不要点击它!
因为用调试证书签名的安装包只能使用 hdc 命令安装到开启了开发者选项的手机上,这不是我们想要的。

我们需要自己到 AppGallery Connect 网站上手动申请用于内部测试的证书文件,然后再填写到这个对话框里。

注意上面的对话框里面有个【运行设备-检测】按钮,只要把开启了开发者选项的手机连接到电脑上,点击这个按钮就可以采集到设备标识。

完整的手动申请证书的操作可以看鸿蒙的官方文档,我这里只简要介绍一下步骤:

这一步需要留意的是你使用的应用包名。

所有需要参与内部分发的手机都要先采集到设备标识,并 提交到 AppGallery Connect,后续申请 profile 文件时需要它们。

这一步你将得到一个私钥库文件(.p12)和一个证书申请文件(.csr)。
请记住你使用的密码,有两个(一个是访问私钥库的密码,另一个是访问私钥的密码,但一般都使用相同的密码)。
也请记住你使用的私钥别名,这些在最后填写【配置调试证书】的时候都会用到。

这一步需要上传 .csr 文件,你将得到一个发布证书文件(.cer),下载到本地备用。

这一步你将得到一个 profile 文件(.p7b),下载到本地备用。
【类型】请选择【内部测试】,【证书】就选择上一步得到的发布证书,【设备】请选上所有需要参与内部分发的手机,你应该已经把它们都提交过了。

做完上面这几步,你就可以回到 HBuilderX 中,打开【配置调试证书】对话框,把所有的内容都填好并保存。
【运行设备】那里只要有当前连接的设备就好了,对于最后生成的 .hap 没有影响。

二. 用 HBuilderX 以【运行到鸿蒙】的方式得到 .hap 安装包

在 HBuilderX 里面点击菜单项【运行>运行到手机或模拟器>运行到鸿蒙】,弹出运行对话框,选择好运行设备,点击【运行】按钮。

正常来说,应用就可以在手机上运行起来了,而你在 HBuilderX 控制台里面可以看到下面这些内容:

红框里的目录就是用于构建鸿蒙运行包的鸿蒙工程目录,在里面能够找到已签名的运行包:

对于内部分发而言,这个运行包就是所需要的安装包了,你可以把它改成一个更合适的名字(比如 my-internal-app.hap)备用。

请记住这个 app-harmony 目录,下一步有些需要的东西得在这个目录里找。

三. 编写内部分发所需要的相关文件,并上传到服务器供用户下载

这里假定你的服务器域名为 www.my-server.com

1. 先上传两个文件,并得到下载链接。

把前面得到的安装包(.hap)上传到你的服务器,得到对应的下载链接,比如 https://www.my-server.com/my-internal-app.hap

再准备两个图片文件,作为下载安装过程中显示的图标。按照鸿蒙官方文档的说法,需要准备一大一小两个图标,但我没有找到关于具体规格的说明,索性就直接用 app-harmony/AppScope/resources/base/media/foreground.png 这个文件把两者都代替了。
上传后也是得到了下载链接,比如 https://www.my-server.com/foreground.png

2. 编写一个内部分发描述文件 manifest.json5

须按照 鸿蒙官方文档 的指导编写这个文件。

由于这个文件编写好之后还需要进行签名,所以我们暂且保存为文件名 manifest-unsigned.json5,签名后将得到 manifest.json5

其中有几个属性值可以从 app-harmony/AppScope/app.json5 文件里找到:

  • bundleName
  • versionCode
  • versionName

还有几个属性需要特别说明一下:

  • minAPIVersiontargetAPIVersion

app-harmony/build-profile.json5 文件中找到 app.products 数组,在里面找到 compatibleSdkVersion 值(可能有多个,但应该是相同的值),把 minAPIVersiontargetAPIVersion 都填成这个值就行了。

  • deployDomain

这个是将来用于提供下载服务的域名,填写你自己实际的服务域名即可,比如前面说的 www.my-server.com

  • icons 里面的 normallarge

这里填写的是将来下载时显示的图标的网址,就填写前面上传图标文件得到的链接地址。

  • modules

此项看上去比较复杂,需要参照 app-harmony/build-profile.json5 文件中的 modules 来改写,每个打包出来的独立模块都要在这里填写。

但实际上,多数情况下构建产物里只会有一个模块,就是主模块(该模块的 nametype 都是 entry),也就是前面提到的 .hap 文件。

  • modules 里面的 packageUrlpackageHash

这里的 package 指的就是前面得到的安装包 .hap 文件,packageUrl 填写的是将来下载安装包时使用的网址,packageHash 填写的是这个安装包文件的 SHA256 哈希值。

  • sign

这一项是对这个描述文件本身的签名,无需手动填写,下一步将使用签名工具来生成它。

写好的 manifest-unsigned.json5 文件大体上会是下面这个样子:

{  
  "app": {  
    "bundleName": "io.dcloud.uniappx",  
    "bundleType": "app",  
    "versionCode": 10907,  
    "versionName": "1.9.7",  
    "label": "Hello uni-app x",  
    "deployDomain": "www.my-server.com",  
    "icons": {  
      "normal": "https://www.my-server.com/foreground.png",  
      "large": "https://www.my-server.com/foreground.png"  
    },  
    "minAPIVersion": "5.0.1(13)",  
    "targetAPIVersion": "5.0.1(13)",  
    "modules": [  
      {  
        "name": "entry",  
        "type": "entry",  
        "deviceTypes": ["phone", "tablet", "2in1"],  
        "packageUrl": "https://www.my-server.com/my-internal-app.hap",  
        "packageHash": "27005caa60761b863fbf0fbcd0f96159386de038f59102f0ec676532cd49b084"  
      }  
    ]  
  }  
}

3. 对描述文件 manifest.json5 做签名并上传。

先下载 签名工具,注意其中的 manifest-sign-tool-1.0.0.jar,用 java 执行它:

java -jar "<manifest-sign-tool-1.0.0.jar的绝对路径>" \  
-operation sign \  
-mode localjks \  
-inputFile "<前面编写的manifest-unsigned.json5文件的绝对路径>" \  
-outputFile "<将要生成的manifest.json5文件的绝对路径>" \  
-keystore "<私钥库.p12文件的绝对路径>" \  
-keystorepasswd <私钥库密码> \  
-keyaliaspasswd <私钥密码> \  
-privatekey <私钥别名>

这样就会得到包含签名的 manifest.json 文件,上传到服务器,得到对应的下载链接,比如 https://www.my-server.com/manifest.json5

4. 编写一个网页文件并上传。

编写一个 index.html 文件,内容如下:

<!DOCTYPE html>  
<html lang="zh-CN">  
  <head>  
    <meta charset="UTF-8"/>  
    <meta name="viewport" content="width=device-width, initial-scale=1"/>  
    <title>企业内部分发</title>  
    <script>  
      function openDeepLink() {  
        let url ='store://enterprise/manifest?url=https://www.my-server.com/manifest.json5'  
        window.open(url, '_parent')  
      }  
    </script>  
  </head>  
  <body>  
    <button onclick="openDeepLink()">下载安装</button>  
  </body>  
</html>

注意里面的下载链接,要替换成你自己实际的链接地址。

index.html 文件上传到服务器,得到对应的下载链接,比如 https://www.my-server.com/index.html

好了,大功告成!

下面只要告诉参与内部分发的用户,用手机里面的鸿蒙官方浏览器打开这个网址,就可以点击其中的按钮下载安装了。

你也可以把这个网址做成二维码,让用户使用手机的浏览器扫码访问,这样会更方便。

收起阅读 »

鸿蒙 UTS 插件使用三方依赖、本地依赖

uts插件

鸿蒙 UTS 插件使用三方依赖

在鸿蒙开发中市场需要使用三方依赖,可能是三方包,可能是一个本地 har 包,这里介绍如何接入。

接入三方依赖

这里举例 https://ohpm.openharmony.cn/ 最受欢迎的三方库 @pura/harmony-utils 。这个库,提供了众多方法,可以加速功能开发。

更新:为了辅助说明,这里提供了 uts 源码,可对比参考 https://ext.dcloud.net.cn/plugin?id=24849

harmony-utils 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类,致力于助力开发者迅速构建鸿蒙应用。其封装的工具涵盖了APP、设备、屏幕、授权、通知、线程间通信、弹框、吐司、生物认证、用户首选项、拍照、相册、扫码、文件、日志,异常捕获、字符、字符串、数字、集合、日期、随机、base64、加密、解密、JSON等一系列的功能和操作,能够满足各种不同的开发需求。

从原生鸿蒙角度开发,使用这个工具库,需要两个步骤

  • 安装依赖
  • 调用方法

在 UTS 中使用这个工具库,需要三个步骤

  • 创建 UTS 插件
  • 引用依赖
  • 调用方法

下面介绍具体步骤

假设我们希望通过 harmony-utils 获取当前的工具包名。调用的是 AppUtil.getBundleName

1. 创建 UTS 插件

在 HBuilderX 中操作。首先创建 uni_modules 功能,如果当前目录中没有对应文件夹,可在项目文件夹节点单击右键选择 新建 uni_modules 目录

这会创建 uni_moduels 文件夹,在这个文件夹上单击右键。

在新窗口中选择 UTS 插件-API 插件,点击创建。

假定插件的 ID 是 invoke-utils,找到这个文件夹,观察是否存在对应的文件,如果没有就创建 uni_modules/invoke-utils/utssdk/app-harmony/index.uts

这样插件就创建好了。这部分可参考 UTS 插件介绍原生混编 做进一步了解。

2. 安装依赖

创建 uni_modules/invoke-utils/utssdk/app-harmony/config.json,添加依赖。可参考文档 配置uts插件依赖

鸿蒙的库管理工具是ohpm。类似于js的npm,Android的仓储。鸿蒙的三方sdk封装文件为.har,类似于Android的.aar
uts插件的utssdk/app-harmony/config.json文件内可以配置依赖使用鸿蒙的三方库

代码填写下面方案:

{  
   "dependencies": {  
     "@pura/harmony-utils":"1.3.6"  
   }  
}

接下来准备使用依赖功能。

3. 调用方法

在 index.uts 中添加下面逻辑

import { AppUtil } from '@pura/harmony-utils'  

UTSHarmony.onAppAbilityCreate(() => {  
  const abilityCtx = UTSHarmony.getUIAbilityContext();  
  const ctx = abilityCtx  
  AppUtil.init(ctx);  
})  

export const getAppId = () => {  
  let bundleName = AppUtil.getBundleName();  
  return bundleName  
}

在原始文档中要求在 AbilityCreate 中初始化,这里可以使用 UTSHarmony.onAppAbilityCreate 来实现初始化。

和 TS 代码类似,调用了提供的方法,返回了具体数据。

在实际的 Vue 逻辑中,比如 button 通过 click 调用下面逻辑即可

<script setup>  
  import { getAppId } from '@/uni_modules/invoke-utils'  
  function openTest() {  
    const res = getAppId()  
    console.log('获取应用ID:', res)  
  }  
</script>

调用此方法,观察控制台,可以看到包名。这说明工具调用成功。

接入 har 依赖

接入 har 依赖。如何制作 har 依赖,在下面单独说明。

假定已经得到了一个 localLib.har 文件。放置 har 文件在 uts 插件内,比如在 index.uts 的同级目录, libs/localLib.har 路径。

修改 config.json,配置相对路径。

{  
  "dependencies": {  
    "locallib": "./libs/localLib.har"  
  }  
}

在 index.uts 中引用和导出。

注意:这里提到的 locaLib 名称不是随便起的,类似于 npm 的 packages.json 依赖, "vue":"3.4" ,这里的 vue 要和实际安装的包名要一致。

包名和导出的内容如何知晓?把 har 包改成 zip 并解压,得到产物。有两个文件需要注意

  • oh-package.json 里面的 name 是包的名字,可以复制出来,不要随意写成 localib 以实际为准
  • 包导出的内容可以在 index.d.ts 中查看,看具体 export 的内容是什么,不要随意写成 add 以实际为准
import { add } from 'locallib'  

export const addFun = (a:number, b:number):number => {  
  return add(a, b)  
}

在页面中引入这个 uts 插件并使用即可。

<script setup>  
  import { addFun} from '@/uni_modules/otto-thirdhar'  
  function openTest() {  
    console.log(addFun(3,4))  
  }  
</script>

执行这个方法,顺利的话可以看到控制台打印数字 7.

注意事项:

  • 引入 har 可能有版本兼容性要求,可在 harmony-configs/build-profile.json5 内修改 compatibleSdkVersion
  • har 可能构建内容有误,实际运行不正常,可在原生工程项目中自测,排除 har 文件内部问题

如何构建 har 模块

在 DevEco 中打开一个项目,选择 文件 - 新建 - 模块 - Static Library,定义模块名选择创建。

在创建的文件中选择 index.ets 找到模块入口,可导出组件、方法。

在 DevEco 中选择 构建(在重构和运行中间) - 构建模块(第一个选项),等待编译结束,观察模块目录中的 build/default/outputs/default 找到 har 文件。

har 文件本身是一个压缩文件,可自行拆包了解结构,内部存在方法 d.ets 等文件。

继续阅读 »

鸿蒙 UTS 插件使用三方依赖

在鸿蒙开发中市场需要使用三方依赖,可能是三方包,可能是一个本地 har 包,这里介绍如何接入。

接入三方依赖

这里举例 https://ohpm.openharmony.cn/ 最受欢迎的三方库 @pura/harmony-utils 。这个库,提供了众多方法,可以加速功能开发。

更新:为了辅助说明,这里提供了 uts 源码,可对比参考 https://ext.dcloud.net.cn/plugin?id=24849

harmony-utils 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类,致力于助力开发者迅速构建鸿蒙应用。其封装的工具涵盖了APP、设备、屏幕、授权、通知、线程间通信、弹框、吐司、生物认证、用户首选项、拍照、相册、扫码、文件、日志,异常捕获、字符、字符串、数字、集合、日期、随机、base64、加密、解密、JSON等一系列的功能和操作,能够满足各种不同的开发需求。

从原生鸿蒙角度开发,使用这个工具库,需要两个步骤

  • 安装依赖
  • 调用方法

在 UTS 中使用这个工具库,需要三个步骤

  • 创建 UTS 插件
  • 引用依赖
  • 调用方法

下面介绍具体步骤

假设我们希望通过 harmony-utils 获取当前的工具包名。调用的是 AppUtil.getBundleName

1. 创建 UTS 插件

在 HBuilderX 中操作。首先创建 uni_modules 功能,如果当前目录中没有对应文件夹,可在项目文件夹节点单击右键选择 新建 uni_modules 目录

这会创建 uni_moduels 文件夹,在这个文件夹上单击右键。

在新窗口中选择 UTS 插件-API 插件,点击创建。

假定插件的 ID 是 invoke-utils,找到这个文件夹,观察是否存在对应的文件,如果没有就创建 uni_modules/invoke-utils/utssdk/app-harmony/index.uts

这样插件就创建好了。这部分可参考 UTS 插件介绍原生混编 做进一步了解。

2. 安装依赖

创建 uni_modules/invoke-utils/utssdk/app-harmony/config.json,添加依赖。可参考文档 配置uts插件依赖

鸿蒙的库管理工具是ohpm。类似于js的npm,Android的仓储。鸿蒙的三方sdk封装文件为.har,类似于Android的.aar
uts插件的utssdk/app-harmony/config.json文件内可以配置依赖使用鸿蒙的三方库

代码填写下面方案:

{  
   "dependencies": {  
     "@pura/harmony-utils":"1.3.6"  
   }  
}

接下来准备使用依赖功能。

3. 调用方法

在 index.uts 中添加下面逻辑

import { AppUtil } from '@pura/harmony-utils'  

UTSHarmony.onAppAbilityCreate(() => {  
  const abilityCtx = UTSHarmony.getUIAbilityContext();  
  const ctx = abilityCtx  
  AppUtil.init(ctx);  
})  

export const getAppId = () => {  
  let bundleName = AppUtil.getBundleName();  
  return bundleName  
}

在原始文档中要求在 AbilityCreate 中初始化,这里可以使用 UTSHarmony.onAppAbilityCreate 来实现初始化。

和 TS 代码类似,调用了提供的方法,返回了具体数据。

在实际的 Vue 逻辑中,比如 button 通过 click 调用下面逻辑即可

<script setup>  
  import { getAppId } from '@/uni_modules/invoke-utils'  
  function openTest() {  
    const res = getAppId()  
    console.log('获取应用ID:', res)  
  }  
</script>

调用此方法,观察控制台,可以看到包名。这说明工具调用成功。

接入 har 依赖

接入 har 依赖。如何制作 har 依赖,在下面单独说明。

假定已经得到了一个 localLib.har 文件。放置 har 文件在 uts 插件内,比如在 index.uts 的同级目录, libs/localLib.har 路径。

修改 config.json,配置相对路径。

{  
  "dependencies": {  
    "locallib": "./libs/localLib.har"  
  }  
}

在 index.uts 中引用和导出。

注意:这里提到的 locaLib 名称不是随便起的,类似于 npm 的 packages.json 依赖, "vue":"3.4" ,这里的 vue 要和实际安装的包名要一致。

包名和导出的内容如何知晓?把 har 包改成 zip 并解压,得到产物。有两个文件需要注意

  • oh-package.json 里面的 name 是包的名字,可以复制出来,不要随意写成 localib 以实际为准
  • 包导出的内容可以在 index.d.ts 中查看,看具体 export 的内容是什么,不要随意写成 add 以实际为准
import { add } from 'locallib'  

export const addFun = (a:number, b:number):number => {  
  return add(a, b)  
}

在页面中引入这个 uts 插件并使用即可。

<script setup>  
  import { addFun} from '@/uni_modules/otto-thirdhar'  
  function openTest() {  
    console.log(addFun(3,4))  
  }  
</script>

执行这个方法,顺利的话可以看到控制台打印数字 7.

注意事项:

  • 引入 har 可能有版本兼容性要求,可在 harmony-configs/build-profile.json5 内修改 compatibleSdkVersion
  • har 可能构建内容有误,实际运行不正常,可在原生工程项目中自测,排除 har 文件内部问题

如何构建 har 模块

在 DevEco 中打开一个项目,选择 文件 - 新建 - 模块 - Static Library,定义模块名选择创建。

在创建的文件中选择 index.ets 找到模块入口,可导出组件、方法。

在 DevEco 中选择 构建(在重构和运行中间) - 构建模块(第一个选项),等待编译结束,观察模块目录中的 build/default/outputs/default 找到 har 文件。

har 文件本身是一个压缩文件,可自行拆包了解结构,内部存在方法 d.ets 等文件。

收起阅读 »

Uniapp 的鸿蒙 next 应用中隐藏和显示系统状态栏

鸿蒙next

本示例至少需要在 HbuilderX 4.61 运行

在 uniapp 开发鸿蒙应用中,通过 UTS 插件,可以调用许多系统原生的 API,这里给出一个小功能:隐藏和显示系统状态栏

原始的界面效果:

隐藏系统状态栏之后的效果:

这个示例的参考文档有:

  • 鸿蒙官方文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-arkui-193
  • UTS 插件: https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html
  • UTSHarmony 的使用: https://doc.dcloud.net.cn/uni-app-x/uts/utsharmony.html

核心页面代码:

<template>  
    <view>  
        <button @click="show">显示原生状态栏</button>  
        <button @click="hide">隐藏原生状态栏</button>  
    </view>  
</template>  
<script>  
    import { showStatusBar, hideStatusBar } from '@/uni_modules/harmony-statusbar';  
    export default {  
        data() {  
            return {  
                message: 'Hello, World!'  
            }  
        },  
        methods: {  
            show() {  
                showStatusBar()  
            },  
            hide() {  
                hideStatusBar()  
            }  
        }  
    }  
</script>  
<style scoped>  
</style>

核心UTS插件代码:

import window from '@ohos.window';  

let _window : window.Window;  

UTSHarmony.onAppAbilityWindowStageCreate((windowStage : window.WindowStage) => {  
    _window = windowStage.getMainWindowSync()  
})  

export const hideStatusBar = () => {  
    _window.setWindowSystemBarEnable([])  
}  

export const showStatusBar = () => {  
    _window.setWindowSystemBarEnable(['status', 'navigation'])  
}

示例工程:

继续阅读 »

本示例至少需要在 HbuilderX 4.61 运行

在 uniapp 开发鸿蒙应用中,通过 UTS 插件,可以调用许多系统原生的 API,这里给出一个小功能:隐藏和显示系统状态栏

原始的界面效果:

隐藏系统状态栏之后的效果:

这个示例的参考文档有:

  • 鸿蒙官方文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-arkui-193
  • UTS 插件: https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html
  • UTSHarmony 的使用: https://doc.dcloud.net.cn/uni-app-x/uts/utsharmony.html

核心页面代码:

<template>  
    <view>  
        <button @click="show">显示原生状态栏</button>  
        <button @click="hide">隐藏原生状态栏</button>  
    </view>  
</template>  
<script>  
    import { showStatusBar, hideStatusBar } from '@/uni_modules/harmony-statusbar';  
    export default {  
        data() {  
            return {  
                message: 'Hello, World!'  
            }  
        },  
        methods: {  
            show() {  
                showStatusBar()  
            },  
            hide() {  
                hideStatusBar()  
            }  
        }  
    }  
</script>  
<style scoped>  
</style>

核心UTS插件代码:

import window from '@ohos.window';  

let _window : window.Window;  

UTSHarmony.onAppAbilityWindowStageCreate((windowStage : window.WindowStage) => {  
    _window = windowStage.getMainWindowSync()  
})  

export const hideStatusBar = () => {  
    _window.setWindowSystemBarEnable([])  
}  

export const showStatusBar = () => {  
    _window.setWindowSystemBarEnable(['status', 'navigation'])  
}

示例工程:

收起阅读 »

uni-app/uniappx 中调用鸿蒙原生扫码能力的实践

鸿蒙next

uni-app/uniappx 中调用鸿蒙原生扫码能力的实践

一、背景介绍

最近在开发一个鸿蒙应用时,遇到了扫码功能的需求。之前用过很多扫码方案,但都不太理想。直到发现了 hmos-scan 这个插件,终于解决了我们的痛点。下面分享一下使用心得。

1.1 为什么选择 hmos-scan?

说实话,之前踩过不少坑:

  1. 传统扫码方案太坑了

    • WebView 扫码慢得要死,经常卡住
    • 引入第三方库后,应用体积直接翻倍
    • 不同手机表现不一样,有的能扫,有的扫不了
    • 稍微模糊一点的码就识别不出来,用户体验太差
  2. 原生开发太痛苦

    • 写原生代码太费时间了
    • 每个平台都要写一遍,累死
    • 维护起来特别麻烦
    • 开发周期太长,老板等不及
  3. hmos-scan 真香

    • 用鸿蒙原生能力,扫码贼快
    • 识别率特别高,歪着扫都能识别
    • 几行代码就搞定了,太方便了
    • 性能好,不占内存
    • 还能从相册选图,太贴心了

1.2 实际使用案例

  1. 电商比价

    // 扫商品码比价  
    async function scanProduct() {  
     try {  
       const barcode = await scanapiSync()  
       // 调用比价接口  
       const priceInfo = await comparePrice(barcode)  
       showPriceResult(priceInfo)  
     } catch (error) {  
       showError('扫码失败,重试一下')  
     }  
    }  
  2. 快递扫描

    // 扫快递单号  
    async function scanExpress() {  
     try {  
       const trackingNumber = await scanapiSync()  
       // 查物流信息  
       const expressInfo = await queryExpress(trackingNumber)  
       showExpressInfo(expressInfo)  
     } catch (error) {  
       showError('扫码失败,重试一下')  
     }  
    }  
  3. 会议签到

    // 扫会议码签到  
    async function scanMeeting() {  
     try {  
       const meetingCode = await scanapiSync()  
       // 验证会议码  
       const checkInResult = await verifyMeeting(meetingCode)  
       showCheckInResult(checkInResult)  
     } catch (error) {  
       showError('签到失败,重试一下')  
     }  
    }  

二、环境准备

  1. 开发工具

    • HBuilderX 3.8.0 或以上版本
    • DevEco Studio(鸿蒙开发必备)
  2. 项目要求

    • 用 uni-app x 框架
    • 选 Vue 3 就对了

三、插件使用

1. 插件安装

  1. 去插件市场:hmos-scan 插件
  2. 下载后导入 HBuilderX 就完事了

四、在项目中使用

1. 基础示例

<!-- pages/index/index.uvue -->  
<template>  
  <view class="content">  
    <button @click="startScan">开始扫描</button>  
    <text v-if="scanResult">扫描结果:{{scanResult}}</text>  
  </view>  
</template>  

<script>  
import { scanapiSync } from "@/uni_modules/hmos-scan/utssdk/app-harmony";  

export default {  
  data() {  
    return {  
      scanResult: ''  
    }  
  },  
  methods: {  
    async startScan() {  
      try {  
        const result = await scanapiSync()  
        this.scanResult = result  
        console.log('扫描结果:', result)  
      } catch (error) {  
        console.error('扫描失败:', error)  
        this.scanResult = '扫描失败'  
      }  
    }  
  }  
}  
</script>  

<style>  
.content {  
  padding: 20px;  
}  
button {  
  margin: 20px 0;  
}  
</style>

2. 高级示例(带历史记录)

<!-- pages/advanced/index.uvue -->  
<template>  
  <view class="container">  
    <view class="scan-area">  
      <button @click="startScan" :disabled="isScanning">  
        {{isScanning ? '扫描中...' : '开始扫描'}}  
      </button>  
    </view>  

    <view class="result-area" v-if="scanHistory.length > 0">  
      <text class="title">扫描历史</text>  
      <view v-for="(item, index) in scanHistory" :key="index" class="history-item">  
        <text class="time">{{item.time}}</text>  
        <text class="content">{{item.content}}</text>  
      </view>  
    </view>  
  </view>  
</template>  

<script>  
import { scanapiSync } from "@/uni_modules/hmos-scan/utssdk/app-harmony";  

export default {  
  data() {  
    return {  
      isScanning: false,  
      scanHistory: []  
    }  
  },  
  methods: {  
    async startScan() {  
      if (this.isScanning) return  

      this.isScanning = true  
      try {  
        const result = await scanapiSync()  
        this.scanHistory.unshift({  
          time: new Date().toLocaleTimeString(),  
          content: result  
        })  
      } catch (error) {  
        console.error('扫描失败:', error)  
      } finally {  
        this.isScanning = false  
      }  
    }  
  }  
}  
</script>  

<style>  
.container {  
  padding: 20px;  
}  
.scan-area {  
  margin-bottom: 20px;  
}  
.result-area {  
  border-top: 1px solid #eee;  
  padding-top: 20px;  
}  
.title {  
  font-size: 16px;  
  font-weight: bold;  
  margin-bottom: 10px;  
}  
.history-item {  
  padding: 10px;  
  border-bottom: 1px solid #eee;  
}  
.time {  
  font-size: 12px;  
  color: #999;  
}  
.content {  
  margin-top: 5px;  
}  
</style>

五、功能特点

  1. 多模式支持

    • 二维码、条形码都能扫
    • 相册选图也支持
  2. 错误处理

    • 各种异常都处理好了
    • 提示信息很友好
    • 日志记录很详细
  3. 用户体验

    • 操作简单,一看就会
    • 有状态反馈,不会卡住
    • 异步处理,不阻塞界面

六、注意事项

  1. 兼容性

    • 只支持鸿蒙系统
    • 确保设备有扫码功能
  2. 性能优化

    • 注意内存使用
    • 及时释放资源
    • 别重复扫描

七、常见问题

  1. 扫描失败

    • 看看设备支不支持
    • 查查日志找原因
  2. 结果解析错误

    • 检查结果格式
    • 处理各种返回类型
    • 加好错误处理

八、总结

用了 hmos-scan 插件后,扫码功能开发变得特别简单。原生功能完整保留,开发体验又好,强烈推荐!

九、参考资料

  1. uni-app x 开发文档
  2. 鸿蒙开发文档
  3. UTS 插件开发指南
  4. hmos-scan 插件下载地址
继续阅读 »

uni-app/uniappx 中调用鸿蒙原生扫码能力的实践

一、背景介绍

最近在开发一个鸿蒙应用时,遇到了扫码功能的需求。之前用过很多扫码方案,但都不太理想。直到发现了 hmos-scan 这个插件,终于解决了我们的痛点。下面分享一下使用心得。

1.1 为什么选择 hmos-scan?

说实话,之前踩过不少坑:

  1. 传统扫码方案太坑了

    • WebView 扫码慢得要死,经常卡住
    • 引入第三方库后,应用体积直接翻倍
    • 不同手机表现不一样,有的能扫,有的扫不了
    • 稍微模糊一点的码就识别不出来,用户体验太差
  2. 原生开发太痛苦

    • 写原生代码太费时间了
    • 每个平台都要写一遍,累死
    • 维护起来特别麻烦
    • 开发周期太长,老板等不及
  3. hmos-scan 真香

    • 用鸿蒙原生能力,扫码贼快
    • 识别率特别高,歪着扫都能识别
    • 几行代码就搞定了,太方便了
    • 性能好,不占内存
    • 还能从相册选图,太贴心了

1.2 实际使用案例

  1. 电商比价

    // 扫商品码比价  
    async function scanProduct() {  
     try {  
       const barcode = await scanapiSync()  
       // 调用比价接口  
       const priceInfo = await comparePrice(barcode)  
       showPriceResult(priceInfo)  
     } catch (error) {  
       showError('扫码失败,重试一下')  
     }  
    }  
  2. 快递扫描

    // 扫快递单号  
    async function scanExpress() {  
     try {  
       const trackingNumber = await scanapiSync()  
       // 查物流信息  
       const expressInfo = await queryExpress(trackingNumber)  
       showExpressInfo(expressInfo)  
     } catch (error) {  
       showError('扫码失败,重试一下')  
     }  
    }  
  3. 会议签到

    // 扫会议码签到  
    async function scanMeeting() {  
     try {  
       const meetingCode = await scanapiSync()  
       // 验证会议码  
       const checkInResult = await verifyMeeting(meetingCode)  
       showCheckInResult(checkInResult)  
     } catch (error) {  
       showError('签到失败,重试一下')  
     }  
    }  

二、环境准备

  1. 开发工具

    • HBuilderX 3.8.0 或以上版本
    • DevEco Studio(鸿蒙开发必备)
  2. 项目要求

    • 用 uni-app x 框架
    • 选 Vue 3 就对了

三、插件使用

1. 插件安装

  1. 去插件市场:hmos-scan 插件
  2. 下载后导入 HBuilderX 就完事了

四、在项目中使用

1. 基础示例

<!-- pages/index/index.uvue -->  
<template>  
  <view class="content">  
    <button @click="startScan">开始扫描</button>  
    <text v-if="scanResult">扫描结果:{{scanResult}}</text>  
  </view>  
</template>  

<script>  
import { scanapiSync } from "@/uni_modules/hmos-scan/utssdk/app-harmony";  

export default {  
  data() {  
    return {  
      scanResult: ''  
    }  
  },  
  methods: {  
    async startScan() {  
      try {  
        const result = await scanapiSync()  
        this.scanResult = result  
        console.log('扫描结果:', result)  
      } catch (error) {  
        console.error('扫描失败:', error)  
        this.scanResult = '扫描失败'  
      }  
    }  
  }  
}  
</script>  

<style>  
.content {  
  padding: 20px;  
}  
button {  
  margin: 20px 0;  
}  
</style>

2. 高级示例(带历史记录)

<!-- pages/advanced/index.uvue -->  
<template>  
  <view class="container">  
    <view class="scan-area">  
      <button @click="startScan" :disabled="isScanning">  
        {{isScanning ? '扫描中...' : '开始扫描'}}  
      </button>  
    </view>  

    <view class="result-area" v-if="scanHistory.length > 0">  
      <text class="title">扫描历史</text>  
      <view v-for="(item, index) in scanHistory" :key="index" class="history-item">  
        <text class="time">{{item.time}}</text>  
        <text class="content">{{item.content}}</text>  
      </view>  
    </view>  
  </view>  
</template>  

<script>  
import { scanapiSync } from "@/uni_modules/hmos-scan/utssdk/app-harmony";  

export default {  
  data() {  
    return {  
      isScanning: false,  
      scanHistory: []  
    }  
  },  
  methods: {  
    async startScan() {  
      if (this.isScanning) return  

      this.isScanning = true  
      try {  
        const result = await scanapiSync()  
        this.scanHistory.unshift({  
          time: new Date().toLocaleTimeString(),  
          content: result  
        })  
      } catch (error) {  
        console.error('扫描失败:', error)  
      } finally {  
        this.isScanning = false  
      }  
    }  
  }  
}  
</script>  

<style>  
.container {  
  padding: 20px;  
}  
.scan-area {  
  margin-bottom: 20px;  
}  
.result-area {  
  border-top: 1px solid #eee;  
  padding-top: 20px;  
}  
.title {  
  font-size: 16px;  
  font-weight: bold;  
  margin-bottom: 10px;  
}  
.history-item {  
  padding: 10px;  
  border-bottom: 1px solid #eee;  
}  
.time {  
  font-size: 12px;  
  color: #999;  
}  
.content {  
  margin-top: 5px;  
}  
</style>

五、功能特点

  1. 多模式支持

    • 二维码、条形码都能扫
    • 相册选图也支持
  2. 错误处理

    • 各种异常都处理好了
    • 提示信息很友好
    • 日志记录很详细
  3. 用户体验

    • 操作简单,一看就会
    • 有状态反馈,不会卡住
    • 异步处理,不阻塞界面

六、注意事项

  1. 兼容性

    • 只支持鸿蒙系统
    • 确保设备有扫码功能
  2. 性能优化

    • 注意内存使用
    • 及时释放资源
    • 别重复扫描

七、常见问题

  1. 扫描失败

    • 看看设备支不支持
    • 查查日志找原因
  2. 结果解析错误

    • 检查结果格式
    • 处理各种返回类型
    • 加好错误处理

八、总结

用了 hmos-scan 插件后,扫码功能开发变得特别简单。原生功能完整保留,开发体验又好,强烈推荐!

九、参考资料

  1. uni-app x 开发文档
  2. 鸿蒙开发文档
  3. UTS 插件开发指南
  4. hmos-scan 插件下载地址
收起阅读 »

uniapp- UTS 插件鸿蒙端开发示例 虽然我们这个示例简单 但是这个是难住很多人的一大步

鸿蒙next uts插件

UTS 插件鸿蒙端开发示例

以上示例已开源
项目地址 请参考 示例代码


前言

虽然这个 UTS 插件鸿蒙端的示例看起来很简单,但说实话,这一步其实难住了不少开发者。很多人第一次做 UTS 插件,尤其是要跑通鸿蒙端,都会在这里卡壳。希望这份文档能帮你少走弯路,顺利迈过这道坎。


基础知识补充

什么是 UTS 插件?

UTS 插件其实就是 uni-app x 扩展 API 的标准插件形式。你可以把它理解成"写一份 TypeScript 风格的代码,编译后在不同平台都能用"。

说个实话,刚接触 uni-app x 的时候,很多人一看到"插件"两个字就头大,觉得一定很复杂。其实 UTS 插件的本质,就是把你想要的原生能力用 TypeScript 包一层,剩下的交给编译器搞定。

UTS 与 ArkTS 的关系

UTS 和 ArkTS 都是基于 TypeScript 的扩展,但有些细节不同。特别注意:鸿蒙端开发时,所有对象字面量都必须定义类型,不能用 any 类型,否则会直接编译报错。

比如 ArkTS 不允许无类型的对象字面量,UTS 会自动帮你加上类型,但你自己写代码时一定要养成良好习惯:

// 错误写法(鸿蒙端会报错)  
const obj = { a: 1 };  

// 正确写法  
interface Obj { a: number }  
const obj: Obj = { a: 1 };  
// 或  
const obj = { a: 1 } as Obj;

你只需要记住:UTS 写的代码,最终会被编译成 ArkTS(.ets)文件,然后就能愉快地调用鸿蒙的原生 API 了。

配置鸿蒙依赖

鸿蒙的依赖管理工具叫 ohpm,和 npm 很像。三方 SDK 用 .har 文件(有点像 Android 的 .aar)。

配置依赖时,记得在 utssdk/app-harmony/config.json 里写清楚:

{  
  "dependencies": {  
    "@cashier_alipay/cashiersdk": "15.8.26",  
    "local-deps": "./libs/local-deps.har"  
  }  
}

注意:config.json 不能有注释,本地依赖路径是相对的。

资源文件与权限配置

  • 插件资源(图片、字体等)放在 utssdk/app-harmony/resources
  • 权限、模块信息等写在 utssdk/app-harmony/module.json5

比如你要用定位权限,可以这样写:

{  
  "module": {  
    "requestPermissions": [  
      {  
        "name": "ohos.permission.LOCATION",  
        "usedScene": { "when": "inuse" },  
        "reason": "$string:permission_location_reason"  
      }  
    ]  
  }  
}

context 获取

很多鸿蒙原生 API 需要 context。大多数场景下直接用 getContext() 就行:

import settings from '@ohos.settings';  
const context: Context = getContext();  
settings.getValue(context, settings.display.SCREEN_BRIGHTNESS_STATUS, (err, value) => {  
  if (err) {  
    console.error(`Failed to get the setting. ${err.message}`);  
    return;  
  }  
  console.log(`SCREEN_BRIGHTNESS_STATUS: ${JSON.stringify(value)}`)  
});

有一次小王同学写插件,死活拿不到 context,结果发现是忘了在页面生命周期里调用,调试了半天才恍然大悟。遇到问题别慌,先查查官方文档和社区经验,很多"坑"其实大家都踩过。


更多细节和常见问题,建议随时查阅官方文档:UTS for HarmonyOS


步骤详解

友情提示:

虽然下面的步骤看起来很基础,但每一步都很关键。尤其是接口定义和鸿蒙端实现,很多人就是在这里卡住的。别嫌简单,能跑通才是王道。

再次强调:鸿蒙端开发时,所有对象字面量都必须定义类型,不能用 any 类型!

第一步:定义插件接口(interface.uts)

目的:

  • 明确插件对外暴露的 API 规范,方便多端实现和 IDE 智能提示。
  • 这是 UTS 插件开发的基础,所有端的实现都要遵循这里定义的接口。

操作:

  • uni_modules/你的插件名/utssdk/ 下新建或编辑 interface.uts 文件。
  • 定义你要暴露的类型、方法签名。例如:
// uni_modules/tt-ost/utssdk/interface.uts  
export type MyApiSync1 = (paramA: string) => string;

第二步:鸿蒙端实现接口(app-harmony/index.uts)

目的:

  • 按照接口定义,实现鸿蒙端的具体逻辑。
  • 这是很多开发者卡壳的地方,需注意导入接口类型、调用鸿蒙 API、正确导出方法。
  • 注意:所有对象字面量都要定义类型,不能用 any!

操作:

  • uni_modules/你的插件名/utssdk/app-harmony/ 下新建或编辑 index.uts 文件。
  • 按照接口定义,实现方法。例如:
// uni_modules/tt-ost/utssdk/app-harmony/index.uts  
import { MyApiSync1 } from '../interface.uts';  
import { promptAction } from '@kit.ArkUI';  

interface ShowToastOptions {  
  message: string;  
}  

export const myApiSync1: MyApiSync1 = function (paramA: string): string {  
  let ddd: ShowToastOptions = { message: paramA };  
  promptAction.showToast(ddd);  
  return paramA;  
}
  • 这里以 Toast 弹窗为例,实际可根据业务需求调用鸿蒙原生能力。

第三步:在页面中调用插件方法

目的:

  • 验证插件功能是否生效。
  • 体验 UTS 跨端调用的便捷性。

操作:

  • 在页面脚本中引入并调用插件方法。例如:
<script>  
import { myApiSync1 } from '@/uni_modules/tt-ost';  
export default {  
  methods: {  
    showToast() {  
      const msg = 'Hello Harmony!';  
      const result = myApiSync1(msg);  
      console.log(result); // 输出: Hello Harmony!  
    }  
  }  
}  
</script>

说明

  • 该插件支持多端,鸿蒙端实现了 myApiSync1,会调用 ArkUI 的 promptAction.showToast
  • 其他端(如 Android/iOS)可根据需要实现对应方法。
  • 适合演示 UTS 跨端插件的基本用法。

如需更多信息,请参考 uni-app x 官方 UTS 插件开发文档

继续阅读 »

UTS 插件鸿蒙端开发示例

以上示例已开源
项目地址 请参考 示例代码


前言

虽然这个 UTS 插件鸿蒙端的示例看起来很简单,但说实话,这一步其实难住了不少开发者。很多人第一次做 UTS 插件,尤其是要跑通鸿蒙端,都会在这里卡壳。希望这份文档能帮你少走弯路,顺利迈过这道坎。


基础知识补充

什么是 UTS 插件?

UTS 插件其实就是 uni-app x 扩展 API 的标准插件形式。你可以把它理解成"写一份 TypeScript 风格的代码,编译后在不同平台都能用"。

说个实话,刚接触 uni-app x 的时候,很多人一看到"插件"两个字就头大,觉得一定很复杂。其实 UTS 插件的本质,就是把你想要的原生能力用 TypeScript 包一层,剩下的交给编译器搞定。

UTS 与 ArkTS 的关系

UTS 和 ArkTS 都是基于 TypeScript 的扩展,但有些细节不同。特别注意:鸿蒙端开发时,所有对象字面量都必须定义类型,不能用 any 类型,否则会直接编译报错。

比如 ArkTS 不允许无类型的对象字面量,UTS 会自动帮你加上类型,但你自己写代码时一定要养成良好习惯:

// 错误写法(鸿蒙端会报错)  
const obj = { a: 1 };  

// 正确写法  
interface Obj { a: number }  
const obj: Obj = { a: 1 };  
// 或  
const obj = { a: 1 } as Obj;

你只需要记住:UTS 写的代码,最终会被编译成 ArkTS(.ets)文件,然后就能愉快地调用鸿蒙的原生 API 了。

配置鸿蒙依赖

鸿蒙的依赖管理工具叫 ohpm,和 npm 很像。三方 SDK 用 .har 文件(有点像 Android 的 .aar)。

配置依赖时,记得在 utssdk/app-harmony/config.json 里写清楚:

{  
  "dependencies": {  
    "@cashier_alipay/cashiersdk": "15.8.26",  
    "local-deps": "./libs/local-deps.har"  
  }  
}

注意:config.json 不能有注释,本地依赖路径是相对的。

资源文件与权限配置

  • 插件资源(图片、字体等)放在 utssdk/app-harmony/resources
  • 权限、模块信息等写在 utssdk/app-harmony/module.json5

比如你要用定位权限,可以这样写:

{  
  "module": {  
    "requestPermissions": [  
      {  
        "name": "ohos.permission.LOCATION",  
        "usedScene": { "when": "inuse" },  
        "reason": "$string:permission_location_reason"  
      }  
    ]  
  }  
}

context 获取

很多鸿蒙原生 API 需要 context。大多数场景下直接用 getContext() 就行:

import settings from '@ohos.settings';  
const context: Context = getContext();  
settings.getValue(context, settings.display.SCREEN_BRIGHTNESS_STATUS, (err, value) => {  
  if (err) {  
    console.error(`Failed to get the setting. ${err.message}`);  
    return;  
  }  
  console.log(`SCREEN_BRIGHTNESS_STATUS: ${JSON.stringify(value)}`)  
});

有一次小王同学写插件,死活拿不到 context,结果发现是忘了在页面生命周期里调用,调试了半天才恍然大悟。遇到问题别慌,先查查官方文档和社区经验,很多"坑"其实大家都踩过。


更多细节和常见问题,建议随时查阅官方文档:UTS for HarmonyOS


步骤详解

友情提示:

虽然下面的步骤看起来很基础,但每一步都很关键。尤其是接口定义和鸿蒙端实现,很多人就是在这里卡住的。别嫌简单,能跑通才是王道。

再次强调:鸿蒙端开发时,所有对象字面量都必须定义类型,不能用 any 类型!

第一步:定义插件接口(interface.uts)

目的:

  • 明确插件对外暴露的 API 规范,方便多端实现和 IDE 智能提示。
  • 这是 UTS 插件开发的基础,所有端的实现都要遵循这里定义的接口。

操作:

  • uni_modules/你的插件名/utssdk/ 下新建或编辑 interface.uts 文件。
  • 定义你要暴露的类型、方法签名。例如:
// uni_modules/tt-ost/utssdk/interface.uts  
export type MyApiSync1 = (paramA: string) => string;

第二步:鸿蒙端实现接口(app-harmony/index.uts)

目的:

  • 按照接口定义,实现鸿蒙端的具体逻辑。
  • 这是很多开发者卡壳的地方,需注意导入接口类型、调用鸿蒙 API、正确导出方法。
  • 注意:所有对象字面量都要定义类型,不能用 any!

操作:

  • uni_modules/你的插件名/utssdk/app-harmony/ 下新建或编辑 index.uts 文件。
  • 按照接口定义,实现方法。例如:
// uni_modules/tt-ost/utssdk/app-harmony/index.uts  
import { MyApiSync1 } from '../interface.uts';  
import { promptAction } from '@kit.ArkUI';  

interface ShowToastOptions {  
  message: string;  
}  

export const myApiSync1: MyApiSync1 = function (paramA: string): string {  
  let ddd: ShowToastOptions = { message: paramA };  
  promptAction.showToast(ddd);  
  return paramA;  
}
  • 这里以 Toast 弹窗为例,实际可根据业务需求调用鸿蒙原生能力。

第三步:在页面中调用插件方法

目的:

  • 验证插件功能是否生效。
  • 体验 UTS 跨端调用的便捷性。

操作:

  • 在页面脚本中引入并调用插件方法。例如:
<script>  
import { myApiSync1 } from '@/uni_modules/tt-ost';  
export default {  
  methods: {  
    showToast() {  
      const msg = 'Hello Harmony!';  
      const result = myApiSync1(msg);  
      console.log(result); // 输出: Hello Harmony!  
    }  
  }  
}  
</script>

说明

  • 该插件支持多端,鸿蒙端实现了 myApiSync1,会调用 ArkUI 的 promptAction.showToast
  • 其他端(如 Android/iOS)可根据需要实现对应方法。
  • 适合演示 UTS 跨端插件的基本用法。

如需更多信息,请参考 uni-app x 官方 UTS 插件开发文档

收起阅读 »