鴻蒙開發Hvigor外掛動態生成程式碼

龙儿筝發表於2024-11-20

Hvigor允許開發者實現自己的外掛,開發者可以定義自己的構建邏輯,並與他人共享。Hvigor主要提供了兩種方式來實現外掛:基於hvigorfile指令碼開發外掛、基於typescript專案開發。下面以基於hvigorfile指令碼開發外掛進行介紹。

基於hvigorfile指令碼開發

基於hvigorfile.ts指令碼開發的方式,其優點是可實現快速開發,直接編輯工程或模組下hvigorfile.ts即可編寫外掛程式碼,不足之處是在多個專案中,無法方便的進行外掛程式碼的複用和共享分發。

  1. 匯入模組依賴。
// 匯入介面
import { HvigorPlugin, HvigorNode } from '@ohos/hvigor'
  1. 編寫外掛程式碼。
    在hvigorfile.ts中定義外掛方法,實現HvigorPlugin介面。
// 實現自定義外掛
function customPlugin(): HvigorPlugin {
    return {
        pluginId: 'customPlugin',
        apply(node: HvigorNode) {
            // 外掛主體
            console.log('hello customPlugin!');
        }
    }
}
  1. 在匯出宣告中使用外掛。
export default {
    system: appTasks,
    plugins:[
        customPlugin()  // 應用自定義Plugin
    ]
}

使用hvigorfile外掛動態生成navigation防混淆檔案

我們在使用navigation的系統路由表時,每次新增新頁面,都需要配置一下release環境防混淆。若將這些頁面放在一個固定的目錄下,則與我們的模組化設計相違背,若命名使用固定的字首或字尾,總感覺有點多餘,手動一個一個的新增,雖然符合我們的程式碼規範設計,但就是有點繁瑣。有沒有更方便的方式來處理這個混淆配置呢?

其實我們可以在寫一個hvigorfilew外掛來自動生成混淆配置檔案。我們自定義一個HvigorPlugin任務,透過OhosHapContext物件讀取module.json5檔案中的routerMap欄位,可以獲取系統路由表的名稱,再讀取profile目錄下的路由表。解析json檔案記憶體,並將頁面路徑寫到一個混淆檔案中,這樣每次編譯時,自動生成防混淆檔案,我們只需要引入這個檔案就可以了。示例如下

import { hapTasks, OhosHapContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin'
import { HvigorPlugin, HvigorNode, FileUtil } from '@ohos/hvigor'

function parseRouterMap(): HvigorPlugin {
  return {
    pluginId: 'parseRouterMap',
    apply(node: HvigorNode) {
      const hapCtx = node.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext
      const moduleJson = hapCtx.getModuleJsonOpt()
      const routerMapName = moduleJson['module']['routerMap'].split(':')[1]
      const dir = hapCtx.getModulePath()
      const srcFile = FileUtil.pathResolve(dir, 'src', 'main', 'resources', 'base', 'profile', `${routerMapName}.json`)
      const json = FileUtil.readJson5(srcFile)
      const routerRuleFile = FileUtil.pathResolve(dir, 'obfuscation-router.txt')
      FileUtil.ensureFileSync(routerRuleFile)
      const routerMapArray = json['routerMap']
      let rules = '-keep-file-name\n'
      for (const element of routerMapArray) {
        const pageSourceFile = element['pageSourceFile']
        const path = pageSourceFile.substring(0, pageSourceFile.lastIndexOf('.'))
        rules += `${path}\n`
      }
      FileUtil.writeFileSync(routerRuleFile, rules)
    }
  }
}

export default {
  system: hapTasks,
  plugins:[parseRouterMap()]
}

編譯後會在entry目錄下生成obfuscation-router.txt防混淆檔案,只要引入這個檔案就可以了。

使用hvigorfile外掛動態生成navigation頁面列舉名稱

我們在我們navigation的push跳轉到新頁面時,都得提前定義好系統路由表中的頁面name,因為使用的name與系統路由表中定義的name不相同時,跳轉頁面則會白屏。有了前面的經驗,其它我們也可以動態生成一個ets檔案,將系統路由表中的頁面名稱自動生成一個列舉,這樣就不用每次配置系統路由表,還是複製一下名稱了。例如我們的系統路由表是這樣的

{
  "routerMap": [
    {
      "name": "dialog",
      "pageSourceFile": "src/main/ets/pages/dialog/DialogPage.ets",
      "buildFunction": "dialogBuilder"
    },
    {
      "name": "web",
      "pageSourceFile": "src/main/ets/pages/web/WebPage.ets",
      "buildFunction": "webBuilder"
    },
    {
      "name": "login",
      "pageSourceFile": "src/main/ets/pages/login/LoginPage.ets",
      "buildFunction": "loginBuilder"
    }
  ]
}

我們現在實現一個hvigorfile外掛,來解析系統路由表中的name欄位,並生成對應的列舉值。示例如下

import { hapTasks, OhosHapContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin'
import { HvigorPlugin, HvigorNode, FileUtil } from '@ohos/hvigor'

function parseRouterMap(): HvigorPlugin {
  return {
    pluginId: 'parseRouterMap',
    apply(node: HvigorNode) {
      const hapCtx = node.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext
      const moduleJson = hapCtx.getModuleJsonOpt()
      const routerMapName = moduleJson['module']['routerMap'].split(':')[1]
      const dir = hapCtx.getModulePath()
      const srcFile = FileUtil.pathResolve(dir, 'src', 'main', 'resources', 'base', 'profile', `${routerMapName}.json`)
      const json = FileUtil.readJson5(srcFile)
      const routerMapFile = FileUtil.pathResolve(dir, 'src', 'main', 'ets', 'Pages.ets')
      FileUtil.ensureFileSync(routerMapFile)
      const routerMapArray = json['routerMap']
      let ss = ''
      for (const element of routerMapArray) {
        const name = element['name']
        ss += `  ${name} = '${name}',\n`
      }
      ss = `export enum Pages {\n${ss}}`
      FileUtil.writeFileSync(routerMapFile, ss)
    }
  }
}

export default {
  system: hapTasks,
  plugins:[parseRouterMap()]
}

我們在ets目錄下生成了一個Pages.ets檔案,並將所有navigation頁面生成對應的列舉值,頁面跳轉時,使用這些列舉值就不怕出錯了。Pages.ets內容如下

export enum Pages {
  dialog = 'dialog',
  web = 'web',
  login = 'login',
}

相關文章