


早期技術(shù)選型時(shí),我曾糾結(jié)過兩種方案:一是做傳統(tǒng)的全屏應(yīng)用,二是直接基于元服務(wù)開發(fā)。對(duì)比后發(fā)現(xiàn),全屏應(yīng)用的安裝門檻會(huì)毀掉 “臨時(shí)使用” 的核心體驗(yàn),而元服務(wù)的卡片形態(tài)正好契合 “快速展示、一鍵操作” 的需求。最終確定核心技術(shù)棧:以元服務(wù)為載體,用 App Linking 實(shí)現(xiàn)跨設(shè)備信息傳遞,配合二維碼生成和 WiFi 信息管理 API,完成從密碼獲取到分享的全流程。
二、開發(fā)攻堅(jiān):元服務(wù)與應(yīng)用關(guān)聯(lián)的實(shí)戰(zhàn)踩坑
鴻蒙早期的開發(fā)文檔還不夠完善,很多能力需要靠調(diào)試摸索。整個(gè)開發(fā)過程中,元服務(wù)卡片的動(dòng)態(tài)渲染和 App Linking 的參數(shù)傳遞,是最耗時(shí)的兩個(gè)攻堅(jiān)點(diǎn),也讓我對(duì)鴻蒙特性的理解從 “文檔認(rèn)知” 變成 “實(shí)操認(rèn)知”。
1. 元服務(wù)卡片:從 “靜態(tài)死數(shù)據(jù)” 到 “動(dòng)態(tài)適配”
項(xiàng)目初期,我用 DevEco Studio 創(chuàng)建了第一個(gè)元服務(wù)工程,在 FormAbility 里寫了個(gè)簡(jiǎn)單的卡片布局:頂部顯示 WiFi 名稱,中間是二維碼,底部加個(gè) “刷新” 按鈕。但測(cè)試時(shí)發(fā)現(xiàn)致命問題:卡片上的 WiFi 信息是寫死在代碼里的,換個(gè) WiFi 環(huán)境就失效,完全不具備實(shí)用性。
要實(shí)現(xiàn)動(dòng)態(tài)更新,就得解決兩個(gè)問題:一是獲取當(dāng)前連接的 WiFi 信息,二是讓卡片實(shí)時(shí)同步數(shù)據(jù)。獲取 WiFi 信息需要申請(qǐng)權(quán)限,早期鴻蒙的權(quán)限管理還比較嚴(yán)格,我在 config.json 里配置了 “ohos.permission.GET_WIFI_INFO” 權(quán)限后,卻發(fā)現(xiàn)首次啟動(dòng)時(shí)權(quán)限申請(qǐng)彈窗不彈出。翻遍開發(fā)者論壇才知道,元服務(wù)的權(quán)限申請(qǐng)需要在 FormAbility 的 onCreate 階段主動(dòng)調(diào)用 requestPermissions 接口,而不是像全屏應(yīng)用那樣自動(dòng)觸發(fā)。
解決權(quán)限問題后,又遇到卡片數(shù)據(jù)同步的難題。元服務(wù)卡片默認(rèn)是緩存渲染的,即使本地 WiFi 信息變了,卡片也不會(huì)自動(dòng)刷新。我嘗試用 FormProvider 的 updateForm 接口,在 WiFi 信息變化時(shí)主動(dòng)更新卡片內(nèi)容。但怎么監(jiān)測(cè) WiFi 變化呢?通過注冊(cè) WiFiEventReceiver 廣播接收器,監(jiān)聽網(wǎng)絡(luò)連接狀態(tài)變化,當(dāng)檢測(cè)到 WiFi 重新連接時(shí),就重新獲取 SSID 和密碼,再調(diào)用 updateForm 接口刷新卡片。這樣一來,卡片就從 “靜態(tài)模板” 變成了 “動(dòng)態(tài)適配當(dāng)前環(huán)境” 的實(shí)用工具。
2. App Linking 配置:讓 “碰一碰” 喚醒元服務(wù)
實(shí)現(xiàn)卡片動(dòng)態(tài)顯示后,下一個(gè)目標(biāo)是 “碰一碰分享”—— 兩臺(tái)鴻蒙設(shè)備靠近時(shí),分享方觸發(fā)分享,接收方直接彈出元服務(wù)卡片。這個(gè)流程的核心是 App Linking 的關(guān)聯(lián)配置,也是早期開發(fā)最容易踩坑的地方。

首先在 AGC 控制臺(tái)創(chuàng)建 App Linking,定義了一個(gè)深度鏈接。但最初測(cè)試時(shí),發(fā)送方觸發(fā)分享后,接收方只是跳轉(zhuǎn)到瀏覽器打開鏈接,并沒有喚醒元服務(wù)。后來才發(fā)現(xiàn),需要在 AGC 的 “應(yīng)用關(guān)聯(lián)” 模塊里,將 App Linking 與元服務(wù)的 Form ID 綁定,同時(shí)在應(yīng)用的 module.json5 文件中配置 skills 節(jié)點(diǎn),指定該鏈接對(duì)應(yīng)的 Action 為 “action.system.open”,Entities 為 “entity.system.browsable”,這樣系統(tǒng)才能識(shí)別到這個(gè)鏈接需要喚醒元服務(wù)而非打開瀏覽器。
另一個(gè)關(guān)鍵是參數(shù)傳遞 —— 分享時(shí)必須把 WiFi 的 SSID 和密碼攜帶到接收方。我將鏈接改造為 “XXX?ssid=MyHomeWiFi&pwd=Test123456”,但直接明文傳遞密碼存在安全風(fēng)險(xiǎn)。于是用 Base64 對(duì)密碼進(jìn)行加密,接收方解析后再解密。
在代碼層面,接收方需要在 EntryAbility 的 onCreate 方法中,從 want 參數(shù)里獲取 uri,解析出 query 參數(shù)后解密,再存入 AppStorage,供元服務(wù)卡片讀取顯示。這段解析代碼看似簡(jiǎn)單,卻因?yàn)樵缙邙櫭傻?URL 解析 API 不支持中文 SSID,導(dǎo)致中文 WiFi 名稱出現(xiàn)亂碼。最終通過 URLEncoder 編碼和解碼,才解決了中文適配問題。
3. 分布式軟總線:實(shí)現(xiàn) “碰一碰” 的近距離觸發(fā)
“碰一碰” 的物理觸發(fā),依賴?guó)櫭傻姆植际杰浛偩€能力。我在分享方的元服務(wù)卡片上添加了一個(gè) “碰一碰分享” 按鈕,點(diǎn)擊后調(diào)用分布式軟總線的 publishData 接口,將加密后的 App Linking 通過近距離通信發(fā)送給周邊設(shè)備。接收方通過 subscribeData 接口監(jiān)聽總線數(shù)據(jù),收到數(shù)據(jù)后解析出 App Linking,再調(diào)用 startAbilityWithWant 方法喚醒元服務(wù)。

測(cè)試時(shí)發(fā)現(xiàn),兩臺(tái)設(shè)備距離超過 10 厘米就無法觸發(fā)通信,后來調(diào)整了分布式軟總線的通信參數(shù),將信號(hào)強(qiáng)度閾值降低,同時(shí)優(yōu)化了數(shù)據(jù)發(fā)送的重試機(jī)制,確保近距離內(nèi)穩(wěn)定傳輸。這樣就實(shí)現(xiàn)了完整的 “點(diǎn)擊分享 - 碰一碰 - 接收方彈出卡片” 流程,接收方無需安裝任何應(yīng)用,就能直接看到 WiFi 二維碼。
三、核心代碼解析:接收方喚醒元服務(wù)的關(guān)鍵邏輯
以下代碼是接收方解析 App Linking 并喚醒元服務(wù)的核心邏輯,包含了 URL 解析、密碼解密和元服務(wù)喚醒三個(gè)關(guān)鍵步驟,也是整個(gè)項(xiàng)目最核心的技術(shù)實(shí)現(xiàn)部分。
export default class MainAbility extends EntryAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'WiFiShare', 'MainAbility onCreate');
// 關(guān)鍵:判斷是否通過App Linking喚醒
if (want.uri) {
this.handleAppLinking(want.uri);
}
}
// 處理App Linking鏈接,解析WiFi信息并喚醒元服務(wù)
private async handleAppLinking(uri: string) {
try {
// 1. 解析URL中的參數(shù)(處理中文SSID編碼問題)
const decodedUri = decodeURIComponent(uri);
const urlObj = new URL(decodedUri);
const ssid = urlObj.searchParams.get('ssid');
const encryptedPwd = urlObj.searchParams.get('pwd');
if (!ssid || !encryptedPwd) {
hilog.error(0x0000, 'WiFiShare', '參數(shù)缺失:ssid或pwd為空');
return;
}
// 2. Base64解密密碼(解決明文傳輸安全問題)
const decoder = new util.Base64Decoder();
const pwdBytes = decoder.decodeSync(encryptedPwd);
const password = util.TextDecoder.create('utf-8').decode(pwdBytes);
hilog.info(0x0000, 'WiFiShare', `解析成功 - SSID: ${ssid}, 密碼: ${password}`);
// 3. 將WiFi信息存入AppStorage,供元服務(wù)卡片讀取
AppStorage.SetOrCreate('sharedSsid', ssid);
AppStorage.SetOrCreate('sharedPassword', password);
// 4. 喚醒元服務(wù)卡片(指定Form ID)
this.launchMetaService();
} catch (error) {
hilog.error(0x0000, 'WiFiShare', `解析App Linking失敗: ${JSON.stringify(error)}`);
}
}
// 喚醒元服務(wù)卡片
private launchMetaService() {
const formWant: Want = {
deviceId: '', // 空表示當(dāng)前設(shè)備
bundleName: 'com.demo.wifishare',
abilityName: 'com.demo.wifishare.FormAbility',
parameters: {
'formId': '10001', // 元服務(wù)卡片的Form ID
'formType': '1' // 1表示臨時(shí)卡片
}
};
// 調(diào)用元服務(wù)啟動(dòng)接口
this.context.startAbility(formWant, (err) => {
if (err) {
hilog.error(0x0000, 'WiFiShare', `啟動(dòng)元服務(wù)失敗: ${JSON.stringify(err)}`);
return;
}
hilog.info(0x0000, 'WiFiShare', '元服務(wù)卡片啟動(dòng)成功');
});
}
}
這段代碼是接收方處理分享的核心流程。首先在 onCreate 方法中判斷是否由 App Linking 喚醒,若存在 uri 則調(diào)用 handleAppLinking 方法解析;解析過程中先處理中文編碼問題,再通過 Base64 解密密碼,確保數(shù)據(jù)傳輸安全;最后將 WiFi 信息存入 AppStorage,并通過 startAbility 接口喚醒元服務(wù)卡片,實(shí)現(xiàn) “接收即顯示” 的無縫體驗(yàn)。
代碼中加入了詳細(xì)的日志打印和異常處理,這是早期調(diào)試?guó)櫭蓱?yīng)用時(shí)必不可少的習(xí)慣,能快速定位參數(shù)解析或卡片啟動(dòng)失敗的問題。
四、體驗(yàn)復(fù)盤與生態(tài)思考:鴻蒙的 “輕” 與 “聯(lián)”
這個(gè) WiFi 密碼分享器,雖然只是個(gè)實(shí)驗(yàn)性項(xiàng)目,卻讓我在鴻蒙生態(tài)早期就摸到了其核心競(jìng)爭(zhēng)力 ——“輕” 與 “聯(lián)” 的結(jié)合。“輕” 體現(xiàn)在元服務(wù)無需安裝的輕量化形態(tài),降低了用戶使用門檻;“聯(lián)” 則通過 App Linking 和分布式軟總線,實(shí)現(xiàn)了設(shè)備間的無縫信息流轉(zhuǎn)。在兩臺(tái)鴻蒙測(cè)試機(jī)上完成首次 “碰一碰” 分享時(shí),接收方瞬間彈出包含 WiFi 二維碼的卡片,那種無需繁瑣操作的流暢感,讓我真切感受到了分布式技術(shù)的價(jià)值。

這個(gè)項(xiàng)目也讓我對(duì)鴻蒙生態(tài)的未來有了更具體的認(rèn)知:它的競(jìng)爭(zhēng)力不在于替代某個(gè)系統(tǒng),而在于通過元服務(wù)、分布式軟總線等能力,重構(gòu) “服務(wù)觸達(dá)用戶” 的方式。就像這個(gè) WiFi 分享工具,它沒有做復(fù)雜的功能,卻通過鴻蒙特性解決了傳統(tǒng)方案的痛點(diǎn)。對(duì)開發(fā)者而言,鴻蒙開發(fā)的核心不是學(xué)習(xí)新的語法,而是轉(zhuǎn)變思維 —— 從 “開發(fā)應(yīng)用” 轉(zhuǎn)變?yōu)?“設(shè)計(jì)場(chǎng)景化服務(wù)”,用輕量化的載體和無縫的連接,讓服務(wù)在需要時(shí)自然出現(xiàn)。
這次探索讓我積累了元服務(wù)和分布式能力的實(shí)戰(zhàn)經(jīng)驗(yàn),也為后續(xù)參與公司的鴻蒙項(xiàng)目打下了基礎(chǔ)。對(duì)我而言,這正是技術(shù)探索的意義:在未成熟的領(lǐng)域里踩坑、復(fù)盤,最終摸清技術(shù)的核心邏輯,等到生態(tài)爆發(fā)時(shí),才能快速抓住機(jī)會(huì)。
4.2 HarmonyOS 6 新啟程
近日,華為正式發(fā)布了新一代鴻蒙操作系統(tǒng) HarmonyOS 6 。新系統(tǒng)在性能、智能體驗(yàn)、安全防護(hù)以及跨設(shè)備協(xié)同方面都帶來了顯著提升。
回想我開發(fā)那個(gè) WiFi 密碼分享器元服務(wù)的經(jīng)歷,當(dāng)時(shí)最深的感觸是:鴻蒙的 “元服務(wù)” 和 “應(yīng)用關(guān)聯(lián)” 像兩顆璀璨但略顯孤立的珍珠,而 HarmonyOS 6 的發(fā)布,仿佛為它們提供了一條更堅(jiān)固的 “項(xiàng)鏈”。新聞中提及的 “星河互聯(lián)架構(gòu)” 和 “一碰多分享”,正是對(duì)我當(dāng)時(shí)所依賴的分布式能力的一次全面升級(jí)。這意味著,未來我不僅能讓用戶 “碰一碰” 分享 WiFi,甚至可以想象,在會(huì)議室里,多人 “碰一碰” 就能瞬間組網(wǎng)并同步會(huì)議議程,這種跨設(shè)備協(xié)同的潛力被極大地拓寬了。

更讓我感到興奮的是 “應(yīng)用智能體” 的規(guī)?;暇€。在我之前的開發(fā)中,元服務(wù)卡片更多是靜態(tài)或簡(jiǎn)單動(dòng)態(tài)的信息展示。而現(xiàn)在,HarmonyOS 6 讓小藝和這些智能體能夠深度理解場(chǎng)景并主動(dòng)服務(wù)。這讓我不禁思考:我那個(gè) WiFi 分享器,能否在下次迭代中進(jìn)化為一個(gè) “場(chǎng)景智能體”?當(dāng)它感知到家里來了新客人,不僅能彈出分享卡片,還能聯(lián)動(dòng)智能家居,主動(dòng)詢問 “是否要為您同步播放客廳的音樂列表”?這種從 “工具” 到 “智能伙伴” 的進(jìn)化,正是 HarmonyOS 6 為我描繪出的全新可能性。

