uniapp開發鴻蒙:原生能力調用實戰

引入:跨平台開發的核心能力

在之前的文章中,我們已經掌握了uniapp在鴻蒙平台下的基礎開發技能。今天,我們將深入探討uniapp調用鴻蒙原生能力的完整方案,這是實現複雜業務功能、提升應用體驗的關鍵環節。

uniapp通過uni-app框架提供了豐富的API,同時支持通過原生插件擴展能力。在鴻蒙平台下,我們還可以直接調用鴻蒙的ArkTS原生能力,實現更底層的功能調用。本文將系統講解這三種方式的實現方案。

一、uni-app內置API調用

1.1 設備信息獲取

獲取設備信息

// 獲取設備信息
uni.getSystemInfo({
  success: (res) => {
    console.log('設備品牌:', res.brand)
    console.log('設備型號:', res.model)
    console.log('系統版本:', res.system)
    console.log('屏幕尺寸:', res.screenWidth, res.screenHeight)
    console.log('DPI:', res.pixelRatio)
  }
})

// 獲取設備基礎信息
const systemInfo = uni.getSystemInfoSync()
console.log('設備信息:', systemInfo)

獲取網絡狀態

// 監聽網絡狀態變化
uni.onNetworkStatusChange((res) => {
  console.log('網絡類型:', res.networkType)
  console.log('是否聯網:', res.isConnected)
})

// 獲取當前網絡狀態
uni.getNetworkType({
  success: (res) => {
    console.log('當前網絡:', res.networkType)
  }
})

1.2 地理位置服務

獲取當前位置

// 獲取當前位置
uni.getLocation({
  type: 'gcj02', // 座標系類型
  success: (res) => {
    console.log('經度:', res.longitude)
    console.log('緯度:', res.latitude)
    console.log('速度:', res.speed)
    console.log('精度:', res.accuracy)
  },
  fail: (err) => {
    console.error('獲取位置失敗:', err)
  }
})

// 持續定位
const locationId = uni.startLocationUpdate({
  type: 'gcj02',
  success: () => {
    console.log('開始持續定位')
  }
})

// 停止定位
uni.stopLocationUpdate({
  success: () => {
    console.log('停止持續定位')
  }
})

1.3 設備傳感器

加速度計

// 監聽加速度計
uni.onAccelerometerChange((res) => {
  console.log('X軸加速度:', res.x)
  console.log('Y軸加速度:', res.y)
  console.log('Z軸加速度:', res.z)
})

// 開始監聽
uni.startAccelerometer({
  interval: 'normal'
})

// 停止監聽
uni.stopAccelerometer()

陀螺儀

// 監聽陀螺儀
uni.onGyroscopeChange((res) => {
  console.log('X軸角速度:', res.x)
  console.log('Y軸角速度:', res.y)
  console.log('Z軸角速度:', res.z)
})

// 開始監聽
uni.startGyroscope({
  interval: 'normal'
})

// 停止監聽
uni.stopGyroscope()

1.4 文件系統操作

文件讀寫

// 讀取文件
uni.getFileSystemManager().readFile({
  filePath: 'file:///path/to/file.txt',
  encoding: 'utf8',
  success: (res) => {
    console.log('文件內容:', res.data)
  }
})

// 寫入文件
uni.getFileSystemManager().writeFile({
  filePath: 'file:///path/to/file.txt',
  data: 'Hello World',
  encoding: 'utf8',
  success: () => {
    console.log('寫入成功')
  }
})

// 獲取文件信息
uni.getFileSystemManager().getFileInfo({
  filePath: 'file:///path/to/file.txt',
  success: (res) => {
    console.log('文件大小:', res.size)
  }
})

二、鴻蒙原生API調用

2.1 權限申請

權限列表

// 檢查權限
uni.authorize({
  scope: 'scope.userLocation',
  success: () => {
    console.log('位置權限已授權')
  },
  fail: () => {
    console.log('位置權限未授權')
  }
})

// 常用權限scope
const PERMISSIONS = {
  LOCATION: 'scope.userLocation', // 位置信息
  CAMERA: 'scope.camera', // 相機
  RECORD: 'scope.record', // 錄音
  USER_INFO: 'scope.userInfo', // 用户信息
  ADDRESS: 'scope.address', // 通訊地址
  INVOICE: 'scope.invoice', // 發票抬頭
  WERUN: 'scope.werun', // 微信運動
  WRITE_PHOTOS: 'scope.writePhotosAlbum' // 保存到相冊
}

2.2 系統能力調用

撥打電話

uni.makePhoneCall({
  phoneNumber: '10086',
  success: () => {
    console.log('撥號成功')
  }
})

發送短信

uni.sendSms({
  phoneNumber: '10086',
  content: 'Hello',
  success: () => {
    console.log('發送成功')
  }
})

打開系統設置

uni.openSetting({
  success: (res) => {
    console.log('設置頁面打開成功')
  }
})

獲取剪貼板內容

uni.getClipboardData({
  success: (res) => {
    console.log('剪貼板內容:', res.data)
  }
})

// 設置剪貼板內容
uni.setClipboardData({
  data: 'Hello World',
  success: () => {
    console.log('複製成功')
  }
})

2.3 設備振動

短振動

uni.vibrateShort({
  success: () => {
    console.log('振動成功')
  }
})

// 長振動
uni.vibrateLong({
  success: () => {
    console.log('長振動成功')
  }
})

2.4 屏幕亮度

獲取屏幕亮度

uni.getScreenBrightness({
  success: (res) => {
    console.log('屏幕亮度:', res.value)
  }
})

// 設置屏幕亮度
uni.setScreenBrightness({
  value: 0.8,
  success: () => {
    console.log('設置亮度成功')
  }
})

// 保持屏幕常亮
uni.setKeepScreenOn({
  keepScreenOn: true,
  success: () => {
    console.log('屏幕常亮開啓')
  }
})

三、原生插件開發

3.1 插件項目結構

創建插件項目

# 創建原生插件項目
npx @dcloudio/uni-plugin create my-plugin

項目結構

my-plugin/
├── android/          # Android原生代碼
├── ios/              # iOS原生代碼
├── harmony/           # 鴻蒙原生代碼
├── package.json
├── plugin.json       # 插件配置文件
└── src/
    └── index.js      # JS接口文件

3.2 鴻蒙原生代碼實現

harmony/ets/MyPlugin.ets

import plugin from '@ohos.hap.plugin'

@Entry
@Component
struct MyPlugin {
  @State message: string = 'Hello World'

  build() {
    Column() {
      Text(this.message)
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
  }
}

// 原生方法實現
export class MyPluginImpl {
  static getDeviceInfo(): string {
    const deviceInfo = deviceInfo.getDeviceInfoSync()
    return JSON.stringify({
      brand: deviceInfo.brand,
      model: deviceInfo.model,
      system: deviceInfo.system
    })
  }

  static showToast(message: string): void {
    prompt.showToast({
      message: message,
      duration: 2000
    })
  }
}

// 註冊插件
plugin.registerPlugin('my-plugin', MyPluginImpl)

3.3 JS接口封裝

src/index.js

// JS接口文件
export default {
  // 獲取設備信息
  getDeviceInfo() {
    return new Promise((resolve, reject) => {
      // 調用鴻蒙原生方法
      const result = uni.requireNativePlugin('my-plugin').getDeviceInfo()
      if (result) {
        resolve(JSON.parse(result))
      } else {
        reject(new Error('獲取設備信息失敗'))
      }
    })
  },

  // 顯示原生Toast
  showToast(message) {
    uni.requireNativePlugin('my-plugin').showToast(message)
  }
}

3.4 插件配置

plugin.json

{
  "name": "my-plugin",
  "id": "my-plugin",
  "version": "1.0.0",
  "description": "自定義原生插件",
  "main": "src/index.js",
  "platforms": ["android", "ios", "harmony"],
  "dependencies": {}
}

3.5 在uniapp中使用插件

安裝插件

# 在uniapp項目中安裝插件
npm install ./my-plugin

在頁面中使用

import myPlugin from 'my-plugin'

// 獲取設備信息
myPlugin.getDeviceInfo().then(info => {
  console.log('設備信息:', info)
})

// 顯示Toast
myPlugin.showToast('Hello from native plugin')

四、ArkTS原生能力調用

4.1 條件編譯調用原生API

在uniapp中調用ArkTS

// #ifdef HARMONYOS
// 鴻蒙平台下調用ArkTS原生API
const { getSystemInfo } = require('@system.app')
getSystemInfo({
  success: (res) => {
    console.log('系統信息:', res)
  }
})
// #endif

// #ifndef HARMONYOS
// 其他平台使用uni-app API
uni.getSystemInfo({
  success: (res) => {
    console.log('系統信息:', res)
  }
})
// #endif

4.2 常用ArkTS API

應用信息

// #ifdef HARMONYOS
const app = require('@system.app')

// 獲取應用信息
app.getInfo({
  success: (res) => {
    console.log('應用名稱:', res.name)
    console.log('版本號:', res.versionName)
  }
})

// 退出應用
app.terminate()
// #endif

路由跳轉

// #ifdef HARMONYOS
const router = require('@system.router')

// 跳轉到頁面
router.push({
  uri: 'pages/index/index'
})

// 返回上一頁
router.back()

// 替換當前頁
router.replace({
  uri: 'pages/detail/detail'
})
// #endif

存儲系統

// #ifdef HARMONYOS
const storage = require('@system.storage')

// 存儲數據
storage.set({
  key: 'token',
  value: 'your_token',
  success: () => {
    console.log('存儲成功')
  }
})

// 讀取數據
storage.get({
  key: 'token',
  success: (res) => {
    console.log('讀取成功:', res.value)
  }
})

// 刪除數據
storage.delete({
  key: 'token',
  success: () => {
    console.log('刪除成功')
  }
})
// #endif

五、跨平台適配方案

5.1 平台判斷

判斷當前平台

// 判斷平台
const platform = uni.getSystemInfoSync().platform

// 條件編譯
// #ifdef HARMONYOS
console.log('當前平台: 鴻蒙')
// #endif

// #ifdef APP-PLUS
console.log('當前平台: App')
// #endif

// #ifdef H5
console.log('當前平台: H5')
// #endif

// #ifdef MP-WEIXIN
console.log('當前平台: 微信小程序')
// #endif

5.2 統一API封裝

封裝跨平台API

// utils/native.js
export const native = {
  // 獲取設備信息
  getDeviceInfo() {
    // #ifdef HARMONYOS
    return new Promise((resolve) => {
      const { getSystemInfo } = require('@system.app')
      getSystemInfo({
        success: resolve
      })
    })
    // #endif
    
    // #ifndef HARMONYOS
    return new Promise((resolve) => {
      uni.getSystemInfo({
        success: resolve
      })
    })
    // #endif
  },

  // 顯示Toast
  showToast(message) {
    // #ifdef HARMONYOS
    const { showToast } = require('@system.prompt')
    showToast({
      message: message,
      duration: 2000
    })
    // #endif
    
    // #ifndef HARMONYOS
    uni.showToast({
      title: message,
      icon: 'none'
    })
    // #endif
  },

  // 撥打電話
  makePhoneCall(phoneNumber) {
    // #ifdef HARMONYOS
    const { makeCall } = require('@system.telephone')
    makeCall({
      number: phoneNumber
    })
    // #endif
    
    // #ifndef HARMONYOS
    uni.makePhoneCall({
      phoneNumber: phoneNumber
    })
    // #endif
  }
}

5.3 在頁面中使用

import { native } from '@/utils/native'

// 獲取設備信息
native.getDeviceInfo().then(info => {
  console.log('設備信息:', info)
})

// 顯示Toast
native.showToast('Hello')

// 撥打電話
native.makePhoneCall('10086')

六、實戰案例:拍照上傳功能

6.1 拍照功能實現

import { native } from '@/utils/native'

export const takePhoto = () => {
  return new Promise((resolve, reject) => {
    // #ifdef HARMONYOS
    const { takePhoto } = require('@system.camera')
    takePhoto({
      success: (res) => {
        resolve(res.uri)
      },
      fail: reject
    })
    // #endif
    
    // #ifndef HARMONYOS
    uni.chooseImage({
      count: 1,
      sourceType: ['camera'],
      success: (res) => {
        resolve(res.tempFilePaths[0])
      },
      fail: reject
    })
    // #endif
  })
}

6.2 圖片上傳功能

import { uploadFile } from '@/utils/upload'

export const uploadPhoto = async () => {
  try {
    // 拍照
    const imagePath = await takePhoto()
    
    // 上傳到服務器
    const result = await uploadFile(imagePath)
    
    // 顯示上傳成功
    native.showToast('上傳成功')
    
    return result
  } catch (error) {
    console.error('拍照上傳失敗:', error)
    native.showToast('上傳失敗')
    throw error
  }
}

6.3 在頁面中使用

<template>
  <view>
    <button @click="handleTakePhoto">拍照上傳</button>
    <image v-if="imageUrl" :src="imageUrl" mode="aspectFill" />
  </view>
</template>

<script setup>
import { ref } from 'vue'
import { uploadPhoto } from '@/utils/photo'

const imageUrl = ref('')

const handleTakePhoto = async () => {
  try {
    const result = await uploadPhoto()
    imageUrl.value = result.url
  } catch (error) {
    console.error('拍照上傳失敗:', error)
  }
}
</script>

七、鴻蒙平台特有配置

7.1 權限配置

manifest.json

{
  "app-plus": {
    "harmony": {
      "requestPermissions": [
        {
          "name": "ohos.permission.CAMERA"
        },
        {
          "name": "ohos.permission.READ_MEDIA"
        },
        {
          "name": "ohos.permission.WRITE_MEDIA"
        },
        {
          "name": "ohos.permission.INTERNET"
        },
        {
          "name": "ohos.permission.LOCATION"
        }
      ]
    }
  }
}

7.2 應用配置

{
  "app-plus": {
    "harmony": {
      "appId": "com.example.myapp",
      "appName": "我的應用",
      "versionName": "1.0.0",
      "versionCode": 100,
      "minPlatformVersion": 9,
      "compileSdkVersion": 9,
      "targetSdkVersion": 9
    }
  }
}

八、常見問題與解決方案

8.1 權限申請失敗

問題:在鴻蒙平台下,部分權限需要動態申請。

解決方案

// 動態申請權限
uni.authorize({
  scope: 'scope.camera',
  success: () => {
    console.log('相機權限已授權')
  },
  fail: () => {
    uni.showModal({
      title: '提示',
      content: '需要相機權限才能使用拍照功能',
      success: (res) => {
        if (res.confirm) {
          uni.openSetting()
        }
      }
    })
  }
})

8.2 原生插件調用失敗

問題:原生插件未正確註冊或配置。

解決方案

  1. 檢查plugin.json配置是否正確
  2. 確認原生代碼已正確編譯
  3. 檢查權限配置是否完整

8.3 跨平台兼容性問題

問題:不同平台API行為不一致。

解決方案

  1. 使用條件編譯區分不同平台
  2. 封裝統一的API接口
  3. 在開發階段充分測試各平台

總結

通過本篇文章的學習,我們掌握了uniapp在鴻蒙平台下調用原生能力的完整方案:

  1. uni-app內置API:設備信息、地理位置、傳感器等基礎能力
  2. 鴻蒙原生API:權限申請、系統能力、設備振動等系統級功能
  3. 原生插件開發:自定義插件的開發、配置和使用
  4. ArkTS原生調用:條件編譯調用鴻蒙原生API
  5. 跨平台適配:統一API封裝和平台判斷
  6. 實戰案例:拍照上傳功能的完整實現

關鍵要點

  • 優先使用uni-app內置API,保證跨平台兼容性
  • 原生插件適用於複雜業務場景和性能優化
  • 條件編譯是實現跨平台適配的有效手段
  • 權限申請是鴻蒙平台下的必要步驟

下一篇文章,我們將深入講解性能優化與調試,包括啓動速度優化、渲染性能優化、內存管理等核心內容,幫助您構建更高效的應用。