鴻蒙學習實戰之路 - 應用間鏈接最佳實踐

應用間鏈接是實現應用間無縫交互的關鍵技術,合理使用可以顯著提升用户體驗

關於本文

本文基於華為官方文檔整理,結合實際開發經驗,提供 HarmonyOS 應用間鏈接的實用指南

華為開發者聯盟 - 應用間鏈接概述

  • 本文並不能代替官方文檔,所有內容基於官方文檔+實踐記錄
  • 所有代碼示例都有詳細註釋,建議自己動手嘗試
  • 基本所有關鍵功能都會附上對應的文檔鏈接,強烈建議你點看看看
  • 本文將通過實際案例介紹應用間鏈接的實現方式和最佳實踐

代碼測試環境

確保你的開發環境符合以下要求:

軟件/工具

版本要求

HarmonyOS SDK

API Level 11+

TypeScript

5.0+

DevEco Studio

4.1+

設備要求

支持 HarmonyOS NEXT 的真機或模擬器

概述

應用間鏈接是指在不同應用之間建立通信和交互的技術。在 HarmonyOS 中,應用間鏈接主要通過以下幾種方式實現:

  1. App Linking:系統級深度鏈接,支持直接跳轉到應用內指定頁面
  2. startAbility:通過能力啓動實現應用間跳轉
  3. Web 攔截跳轉:在 Web 場景下實現應用間跳轉

應用場景示例

社交分享跳轉

  • 用户 A 在社交應用中看到一篇文章,通過分享功能發送給好友 B
  • 好友 B 點擊鏈接後,直接打開社交應用並定位到該篇文章,而非應用首頁

鴻蒙學習實戰之路 - 應用間鏈接最佳實踐_Web

廣告跳轉

  • 視頻應用中播放汽車商城應用的促銷廣告
  • 點擊廣告後直接打開電商應用並跳轉至促銷活動頁面,用户無需在應用內搜索或導航

鴻蒙學習實戰之路 - 應用間鏈接最佳實踐_應用間跳轉_02

特殊文本識別跳轉

  • 聊天界面識別到電話號碼
  • 用户點擊電話號碼後直接打開系統撥號界面,方便用户撥打電話

鴻蒙學習實戰之路 - 應用間鏈接最佳實踐_應用間跳轉_03

本文將從以下幾個方面介紹 HarmonyOS 應用間鏈接的最佳實踐:

  1. App Linking 的基本概念和使用方法
  2. startAbility 實現應用間跳轉
  3. Web 攔截跳轉的實現方式
  4. 應用間鏈接的安全考慮
  5. 實際案例分析

1. App Linking 基本概念和使用

1.1 什麼是 App Linking

App Linking(應用鏈路)是 HarmonyOS 操作系統提供的一項系統級深度鏈接功能,它允許用户通過 HTTPS 鏈接直接跳轉到應用中的指定頁面,無論應用是否已安裝。

1.2 App Linking 的優勢

  • 統一鏈接:同一個鏈接可以在不同平台和場景下使用
  • 跨應用跳轉:支持在不同 HarmonyOS 應用之間無縫跳轉
  • 靈活配置:可以自定義鏈接的行為和參數
  • 用户體驗好:無需用户手動查找應用,直接跳轉至目標頁面
  • 延遲鏈接:支持應用安裝後恢復之前的跳轉意圖

鴻蒙學習實戰之路 - 應用間鏈接最佳實踐_應用間跳轉_04

基於安全性和用户體驗的全面考量,建議優先採用 App Linking 技術。與 Deep Linking 相比,App Linking 提供了更高的安全性,避免了仿冒風險,並提升了用户在應用間跳轉時的整體使用體驗。

1.3 實現 App Linking

1.3.1 配置應用鏈接信息

module.json5 中配置應用鏈接信息:

{
  module: {
    name: "entry",
    type: "entry",
    description: "應用入口模塊",
    mainElement: "EntryAbility",
    deviceTypes: ["phone", "tablet"],
    distro: {
      deliveryWithInstall: true,
      moduleName: "entry",
      moduleType: "entry",
    },
    abilities: [
      {
        name: "EntryAbility",
        srcEntry: "./ets/entryability/EntryAbility.ts",
        description: "應用入口能力",
        icon: "$media:icon",
        label: "應用間鏈接示例",
        startWindowIcon: "$media:icon",
        startWindowBackground: "$color:start_window_background",
        skills: [
          {
            entities: ["entity.system.home"],
            actions: ["action.system.home"],
          },
          {
            actions: ["ohos.want.action.viewData"],
            uris: [
              {
                scheme: "https",
                host: "example.com",
                path: "/app/*",
              },
            ],
          },
        ],
      },
    ],
  },
}
1.3.2 處理鏈接跳轉

EntryAbility.ts 中處理鏈接跳轉:

import { UIAbility, Want, AbilityConstant } from "@kit.AbilityKit";
import { hilog } from "@kit.PerformanceAnalysisKit";
import { Configuration } from "@kit.ConfigurationKit";

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    hilog.info(0x0000, "EntryAbility", "%{public}s", "Ability onCreate");

    // 處理應用鏈接跳轉
    this.handleAppLinking(want);
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
    hilog.info(0x0000, "EntryAbility", "%{public}s", "Ability onNewWant");

    // 處理新的應用鏈接跳轉
    this.handleAppLinking(want);
  }

  // 處理應用鏈接跳轉的方法
  private handleAppLinking(want: Want) {
    if (want.uri) {
      hilog.info(
        0x0000,
        "EntryAbility",
        "Received app linking: %{public}s",
        want.uri
      );

      // 解析 URI 參數
      const url = new URL(want.uri);
      const path = url.pathname;
      const params = new URLSearchParams(url.search);

      // 根據路徑和參數執行相應操作
      if (path.startsWith("/app/detail")) {
        const id = params.get("id");
        if (id) {
          // 跳轉到詳情頁
          this.context.startAbility({
            bundleName: this.context.applicationInfo.bundleName,
            abilityName: "DetailAbility",
            parameters: {
              itemId: id,
            },
          });
        }
      }
    }
  }

  onDestroy() {
    hilog.info(0x0000, "EntryAbility", "%{public}s", "Ability onDestroy");
  }

  onWindowStageCreate(windowStage: any) {
    // 設置主頁面
    windowStage.loadContent("pages/Index", (err, data) => {
      if (err.code) {
        hilog.error(
          0x0000,
          "EntryAbility",
          "Failed to load content: %{public}s",
          JSON.stringify(err)
        );
        return;
      }
    });
  }

  // 其他生命週期方法...
}
1.3.3 發起 App Linking 跳轉

在其他應用中發起 App Linking 跳轉:

import { businessError } from "@kit.BasicServicesKit";
import { openLink } from "@kit.LinkKit";

// 發起應用鏈接跳轉
async function launchAppLinking() {
  try {
    await openLink({
      url: "https://example.com/app/detail?id=12345",
    });
    console.log("App linking launched successfully");
  } catch (error) {
    console.error("Failed to launch app linking:", error as businessError);
  }
}

2. 使用 startAbility 實現應用間跳轉

2.1 startAbility 概述

startAbility 是 HarmonyOS 提供的一種能力啓動機制,可以用於在不同應用之間跳轉,支持傳遞複雜參數。

2.2 實現應用間跳轉

2.2.1 配置能力信息

在目標應用的 module.json5 中配置能力信息:

{
  module: {
    abilities: [
      {
        name: "DetailAbility",
        srcEntry: "./ets/abilities/DetailAbility.ts",
        description: "詳情頁能力",
        icon: "$media:icon",
        label: "詳情頁",
        skills: [
          {
            actions: ["ohos.want.action.detailView"],
            entities: ["entity.system.default"],
          },
        ],
      },
    ],
  },
}
2.2.2 發起能力跳轉

在源應用中發起能力跳轉:

import { context } from "@kit.ArkUI";
import { businessError } from "@kit.BasicServicesKit";

// 發起應用間能力跳轉
async function startOtherAbility() {
  try {
    await context.startAbility({
      bundleName: "com.example.targetapp",
      abilityName: "DetailAbility",
      action: "ohos.want.action.detailView",
      parameters: {
        itemId: "12345",
        itemName: "示例商品",
        itemPrice: 99.9,
      },
    });
    console.log("Ability launched successfully");
  } catch (error) {
    console.error("Failed to launch ability:", error as businessError);
  }
}
2.2.3 接收能力參數

在目標應用的 DetailAbility.ts 中接收參數:

import { UIAbility, Want, AbilityConstant } from "@kit.AbilityKit";
import { hilog } from "@kit.PerformanceAnalysisKit";

export default class DetailAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    hilog.info(0x0000, "DetailAbility", "%{public}s", "Ability onCreate");

    // 接收參數
    if (want.parameters) {
      const itemId = want.parameters.itemId;
      const itemName = want.parameters.itemName;
      const itemPrice = want.parameters.itemPrice;

      hilog.info(
        0x0000,
        "DetailAbility",
        "Received params: id=%{public}s, name=%{public}s, price=%{public}f",
        itemId,
        itemName,
        itemPrice
      );

      // 保存參數,供頁面使用
      this.context.abilityInfo.parameters = want.parameters;
    }
  }

  // 其他生命週期方法...
}

3. Web 攔截跳轉

3.1 Web 攔截跳轉概述

Web 攔截跳轉是指在應用中加載 Web 頁面時,攔截特定的 URL 請求並跳轉到應用內的相應頁面。

3.2 實現 Web 攔截跳轉

import { Web } from '@kit.ArkUI';
import { WebviewController } from '@kit.ArkUI';
import { context } from '@kit.ArkUI';

@Entry
@Component
struct WebPage {
  private webviewController: WebviewController = new WebviewController();

  build() {
    Column() {
      Web({
        src: 'https://example.com',
        controller: this.webviewController
      })
      .javaScriptAccess(true)
      .onUrlLoadIntercept((event) => {
        const url = event.url;

        // 攔截特定 URL
        if (url.startsWith('https://example.com/app/')) {
          // 解析 URL 參數
          const urlObj = new URL(url);
          const path = urlObj.pathname;
          const params = new URLSearchParams(urlObj.search);

          // 根據路徑跳轉到應用內頁面
          if (path.startsWith('/app/detail')) {
            const id = params.get('id');
            if (id) {
              // 跳轉到詳情頁
              router.pushUrl({
                url: `pages/DetailPage?id=${id}`
              });
            }
          }

          // 阻止默認的 URL 加載
          return true;
        }

        // 允許其他 URL 正常加載
        return false;
      })
    }
  }
}

4. 應用間鏈接的安全考慮

4.1 驗證鏈接來源

在處理應用間鏈接時,應該驗證鏈接的來源和完整性,防止惡意鏈接攻擊。

// 驗證鏈接來源
private validateLink(url: string): boolean {
  try {
    const urlObj = new URL(url);

    // 驗證域名
    const allowedDomains = ['example.com', 'trusted-domain.com'];
    if (!allowedDomains.includes(urlObj.host)) {
      console.error('Invalid domain:', urlObj.host);
      return false;
    }

    // 驗證路徑
    if (!urlObj.pathname.startsWith('/app/')) {
      console.error('Invalid path:', urlObj.pathname);
      return false;
    }

    return true;
  } catch (error) {
    console.error('Invalid URL:', error);
    return false;
  }
}

4.2 限制敏感操作

對於涉及敏感操作的鏈接,應該要求用户確認或進行身份驗證。

// 處理敏感操作鏈接
private handleSensitiveLink(url: string) {
  if (url.includes('/app/payment')) {
    // 要求用户確認
    promptAction.showDialog({
      title: '支付確認',
      message: '您確定要進行支付操作嗎?',
      buttons: [
        { text: '取消', color: '#FF0000' },
        { text: '確認', color: '#007DFF' }
      ]
    }).then(result => {
      if (result.index === 1) {
        // 用户確認後執行支付操作
        this.processPayment(url);
      }
    });
  }
}

5. 應用間鏈接最佳實踐總結

5.1 選擇合適的鏈接方式

鏈接方式

適用場景

優勢

App Linking

需要跨平台、跨應用的統一鏈接

統一鏈接,用户體驗好

startAbility

需要傳遞複雜參數的應用間跳轉

參數傳遞靈活,功能強大

Web 攔截跳轉

Web 頁面中的應用內跳轉

無縫集成 Web 和原生頁面

5.2 設計原則

  1. 簡潔明瞭:鏈接地址應該簡潔易記,避免複雜的參數
  2. 一致性:同一功能的鏈接在不同場景下應該保持一致
  3. 可測試性:鏈接應該易於測試和調試
  4. 可擴展性:鏈接設計應該考慮未來功能擴展的需要

5.3 性能優化

  1. 減少參數大小:避免在鏈接中傳遞過大的參數
  2. 異步處理:鏈接處理邏輯應該異步執行,避免阻塞主線程
  3. 緩存機制:對於頻繁訪問的鏈接,可以考慮使用緩存

結語

應用間鏈接是 HarmonyOS 應用開發中的重要技術,可以顯著提升應用間的交互體驗。本文介紹了三種主要的應用間鏈接方式:App Linking、startAbility 和 Web 攔截跳轉,並提供了詳細的實現代碼和最佳實踐。

希望本文的內容能夠對你有所幫助,祝你在鴻蒙開發之路上越走越遠!


參考文檔

  • 華為開發者聯盟 - 應用間鏈接概述
  • HarmonyOS API 參考 - LinkKit
  • HarmonyOS API 參考 - AbilityKit