【鸿蒙进阶-7】鸿蒙与web混合开发

1.简介

什么是混合开发?

混合开发是一种融合了 原生开发 和 Web开发优势 的移动应用开发方式。

具体来说,混合开发通常指的是利用一种框架或平台来创建应用程序,这种程序结合了原生应用的一些功能和特性(比如访问设备的摄像头、相册、GPS、蓝牙等),并且使用Web技术(HTML5、CSS和JavaScript)来编写大部分的应用代码。

混合开发优势

混合开发在跨平台能力、性能、开发效率、更新、离线运行、业务灵活性等方面都有显著优势,这些优势使混合开发成为许多开发者和企业的首选开发模式。

  1. 跨平台能力:混合开发的一个主要优点是可以编写一次代码,然后部署到多个平台(如iOS/Android/HarmonyOS),这大大节省了开发和维护成本。
  2. 快速迭代:由于混合应用主要使用Web技术,因此它们可以像网页一样进行快速更新和迭代,无需用户手动更新应用。
  3. 用户体验:虽然混合应用在性能上可能不如完全的原生应用,但随着技术的发展,许多混合开发框架已经能够提供接近原生应用的用户体验。
  4. 成本效益:对于预算有限的项目或初创公司来说,混合开发是一个成本效益较高的选择,因为它减少了为每个平台单独开发应用的需要。

2.鸿蒙使用web

提供具有网页显示能力的Web组件,@ohos.web.webview提供web控制能力。

复制代码
src: ResourceStr = 'https://m.suning.com'  // 加载的页面地址
// 页面视图控制器
controller = new webview.WebviewController()
  // web组件: 用于加载在线网页
  Web({ src: this.src, controller: this.controller })

// web组件: 用于加载在线网页
Web({ src: this.src, controller: this.controller })
  .onProgressChange((data) => { // 网页加载进度变化时触发该回调
    // 1. 进度条
    console.log('mk-logger', JSON.stringify(data)) // 新的加载进度,取值范围为0到100的整数
    if (data) {
      // 1.1 记录加载进度
      this.progress = data.newProgress
      // 1.2 如果加载进度完成
      if (data.newProgress === 100) {
        // 1.3 动画让进度条消失
        animateTo({ duration: 300, delay: 300 }, () => {
          this.loading = false
        })
      }
    }
  })
  .onPageBegin(() => { // 开始加载网页时触发
    this.progress = 0
    this.loading = true
    console.log('mk-logger', 'onPageBegin')
  })
  .onPageEnd(() => { // 网页加载完成时触发
    console.log('mk-logger', 'onPageEnd')
  })

onPageBegin: 开始加载网页时触发

onPageEnd: 网页加载完成时触发

onProgressChange: 网页加载进度变化时触发该回调

复制代码
// ...
// 加载网页页面完成时触发该回调,用于应用更新其访问的历史链接
.onRefreshAccessedHistory(() => { 
  const history = this.controller.getBackForwardEntries()  // 获取当前Webview的历史信息列表
  this.historyCurrIndex = history.currentIndex  // 当前在页面历史列表中的索引
  this.historySize = history.size  // 历史列表中索引的数量,最多保存50条,超过时起始记录会被覆盖
  // AlertDialog.show({message: this.historyCurrIndex + '-' + this.historySize })
 })
// 
  webBack() {
    // 如果在web容器中, 当前页面之前还有页面, 则容器内返回上一页
    if (this.historyCurrIndex > 0) {
      this.controller.backward()
    } else {
      router.back()
    }
  }

  webClose() {
    router.back()
  }

当页面加载完毕拿到获取当前Webview的历史信息列表

如果该页面之前有 web 页面则返回 web 页面,否则则返回鸿蒙页面

就可以理解为鸿蒙在它的系统底层直接实现了一个浏览器

3.web 端调用鸿蒙原生能力

@ohos.web.webview提供web控制能力,Web组件提供网页显示的能力。

实现语法: registerJavaScriptProxy(object: object, name: string, methodList: Array<string>): void

复制代码
webInit() {
    this.controller.registerJavaScriptProxy({ 
      // 参与注册的应用侧JavaScript对象。
      // 注册对象的名称,与window中调用的对象名一致。
      // 注册后window对象可以通过此名字访问应用侧JavaScript对象。
      // ...
    }, 'mk', [  
      // 参与注册的应用侧JavaScript对象的方法。
      // ...
    ])
}

// ...

Web({ src: this.src, controller: this.controller })
.onAppear(() => {  // 组件挂载显示时触发此回调
   this.webInit()
 })

import { auth, MkUser } from '../utils/auth'

webInit() {
    this.controller.registerJavaScriptProxy({ 
      queryUser: (): MkUser => auth.queryUser(), // 查询用户
      removeUser: (): void => auth.removeUser(), // 移除用户
      updateUser: (user: MkUser): void => auth.updateUser(user),  // 更新用户
    }, 'mk', [  
      'queryUser',
      'updateUser',
      'removeUser',
    ])
}

auth 实现封装了 Appstorage 获取数据并传递

拍照服务 mk.pickerCamera

相机选择器

文件管理

Util工具函数

  1. 打开相机后置摄像头得到拍照结果集

  2. 根据结果集的URI属性同步打开文件

  3. 以同步方法获取文件详细属性信息

  4. 定义缓冲区用于保存读取的文件

  5. 开始同步读取内容到缓冲区

  6. 读取完毕后关闭文件流

  7. 借助util工具方法把读取的文件流转成base64编码的字符串

    import { camera, cameraPicker } from '@kit.CameraKit';
    import fs from '@ohos.file.fs';
    import { util } from '@kit.ArkTS';

    class CameraPlugin {
    async pickerCamera(){
    // 1. 打开相机后置摄像头得到拍照结果集
    const pickerProfile: cameraPicker.PickerProfile = {
    cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
    };
    const pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(),
    [cameraPicker.PickerMediaType.PHOTO], pickerProfile);

    复制代码
       // 2. 根据结果集的URI属性同步打开文件
       const file = fs.openSync(pickerResult.resultUri)
       // 3. 同步读取文件的详情信息
       const stat = fs.statSync(file.fd)
       // 4. 定义缓冲区用于保存读取的文件
       const buffer = new ArrayBuffer(stat.size)
       // 5. 开始同步读取内容到缓冲区
       fs.readSync(file.fd, buffer)
       // 6. 读取完毕后关闭文件流
       fs.closeSync(file)
    
    
       // 7. 借助util工具方法把读取的文件流转成base64编码的字符串
       const helper = new util.Base64Helper()
       const str = helper.encodeToStringSync(new Uint8Array(buffer))
       console.log('mk-logger', 'pickerCamera', str)
       return str
    }

    }

    export const cameraPlugin = new CameraPlugin()

    import { cameraPlugin } from '../plugins/CameraPlugin'

    webInit() {
    this.controller.registerJavaScriptProxy({
    queryUser: (): MkUser => auth.queryUser(), // 查询用户
    removeUser: (): void => auth.removeUser(), // 移除用户
    updateUser: (user: MkUser): void => auth.updateUser(user), // 更新用户
    pickerCamera: (): Promise => cameraPlugin.pickerCamera(), // 调用相机
    }, 'mk', [
    'queryUser',
    'updateUser',
    'removeUser',
    'pickerCamera',
    ])
    }

相册服务 mk.pickerPhoto

相册选择器

新版API

复制代码
import { picker } from '@kit.CoreFileKit'
import fs from '@ohos.file.fs';
import { util } from '@kit.ArkTS';

class PhotoPlugin {
  async pickerPhoto(){
    // 1. 打开相册选择图片
    let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
    PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
    PhotoSelectOptions.maxSelectNumber = 5;
    let photoPicker = new photoAccessHelper.PhotoViewPicker();

    const res = await photoPicker.select(PhotoSelectOptions)
    console.log('mk-logger', 'photoPlugin', JSON.stringify(res))

    // 2. 文件操作
    // 2.1 获取照片的uri地址
    const uri = res.photoUris[0]
    // 2.2 根据uri同步打开文件
    const file = fs.openSync(uri)
    // 2.3 同步获取文件的详细信息
    const stat = fs.statSync(file.fd)
    // 2.4 创建缓冲区存储读取的文件流
    const buffer = new ArrayBuffer(stat.size)
    // 2.5 开始同步读取文件流到缓冲区
    fs.readSync(file.fd, buffer)
    // 2.6 关闭文件流
    fs.closeSync(file)

    // 3. 转成base64编码的字符串
    const helper = new util.Base64Helper()
    const str = helper.encodeToStringSync(new Uint8Array(buffer))
    console.log('mk-logger', 'photoPlugin-str', str)

    return str
   }
}


export const photoPlugin = new PhotoPlugin()

import { photoPlugin } from '../plugins/PhotoPlugin'

webInit() {
    this.controller.registerJavaScriptProxy({ 
      queryUser: (): MkUser => auth.queryUser(), // 查询用户
      removeUser: (): void => auth.removeUser(), // 移除用户
      updateUser: (user: MkUser): void => auth.updateUser(user),  // 更新用户
      pickerCamera: (): Promise<string> => cameraPlugin.pickerCamera(), // 调用相机
      pickerPhoto: (): Promise<string> => photoPlugin.pickerPhoto(),  // 调用相册
    }, 'mk', [  
      'queryUser',
      'updateUser',
      'removeUser',
      'pickerCamera',
    ])
}

拍照服务和相册服务本质上是将图片转换成2进制Buffer流,再将数据传递给web

Sensor Service Kit简介

使用场景

Sensor Service Kit(传感器服务)使应用程序能够从传感器获取原始数据,并提供振感控制能力。

  • 传感器模块是应用访问底层硬件传感器的一种设备抽象概念。开发者可根据传感器提供的相关接口订阅传感器数据,并根据传感器数据定制相应的算法开发各类应用,比如指南针、运动健康、游戏等。
  • 振动模块最大化开放马达器件能力,通过拓展马达服务实现振动与交互融合设计,打造细腻精致的一体化振动体验和差异化体验,提升用户交互效率和易用性、提升用户体验、增强品牌竞争力。

约束限制

Sensor(传感器)

  • 要使用传感器的功能,设备必须具有对应的传感器器件。
  • 针对某些传感器,开发者需要请求相应的权限,才能获取到相应传感器的数据。
  • 传感器数据订阅和取消订阅接口成对调用,当不再需要订阅传感器数据时,开发者需要调用取消订阅接口停止数据上报。

Vibrator(振动)

  • 要使用振动的功能,设备必须具有对应的器件。

  • 针对马达,开发者需要请求相应的权限才能使用

    import { vibrator } from '@kit.SensorServiceKit'

    class SensorPlugin {
    vibrator() {
    vibrator.startVibration({ type: 'time', duration: 50 }, { usage: 'touch' })
    }
    }

    export const sensorPlugin = new SensorPlugin()

    // ...
    import { sensorPlugin } from '../plugins/SensorPlugin'

    webInit() {
    this.controller.registerJavaScriptProxy({
    queryUser: (): MkUser => auth.queryUser(), // 查询用户
    removeUser: (): void => auth.removeUser(), // 移除用户
    updateUser: (user: MkUser): void => auth.updateUser(user), // 更新用户
    pickerCamera: (): Promise => cameraPlugin.pickerCamera(), // 调用相机
    pickerPhoto: (): Promise => photoPlugin.pickerPhoto(), // 调用相册
    vibrator: (): void => sensorPlugin.vibrator(), // 调用传感器
    }, 'mk', [
    'queryUser',
    'updateUser',
    'removeUser',
    'pickerCamera',
    ])
    }

相关推荐
IT_陈寒11 分钟前
Vue的数组更新把我坑惨了
前端·人工智能·后端
于航24 分钟前
分层上下文压缩,幻觉检测,错误累积概要
前端
数据掘金25 分钟前
鸿蒙统计的权限弹窗怎么适配?
前端
数据掘金28 分钟前
鸿蒙统计的多设备协同数据怎么打通?
前端
尘中远30 分钟前
Qwt7的曲线渲染平滑实现:高斯卷积、Savitzky-Golay 回归与特征保护
前端
Fly1 小时前
我来提需求,你带着 Codex 做项目:AI 全栈课程开始实战了
前端
集智飞行2 小时前
解决mavros2 ros2版本cpu占用高的问题
java·服务器·前端
HSunR3 小时前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库
拆房老料4 小时前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
yumgpkpm4 小时前
Acceldata ODP 3.3.6.4 vs CDP Private Cloud Base 7.3.2 对比
大数据·运维·服务器·hadoop·华为·zookeeper·hbase