前言
現(xiàn)在隨著個(gè)人設(shè)備越來越多侍芝,越來越需要多個(gè)設(shè)備之間相互感知和連接凉泄,設(shè)備和設(shè)備之間可以相互聯(lián)動(dòng),形成互聯(lián)互通的場景清钥,而搭載HarmonyOS的設(shè)備恰好可以滿足這一點(diǎn) 琼锋。下面通過開發(fā)一個(gè)HarmonyOS的多端分布式表白應(yīng)用來實(shí)現(xiàn)設(shè)備之間的相互聯(lián)動(dòng)。
項(xiàng)目介紹
H5頁面可以實(shí)現(xiàn)一些比較特殊的頁面效果祟昭,所以選擇在應(yīng)用中集成H5頁面缕坎。應(yīng)用可以將頁面直接投放到附近其他HarmonyOS設(shè)備上,實(shí)現(xiàn)多端設(shè)備分布式顯示篡悟,同時(shí)應(yīng)用可以跨端控制谜叹,更新應(yīng)用頁面,形成多設(shè)備協(xié)同的效果搬葬。
下面是效果展示:
多設(shè)備協(xié)同原理
HarmonyOS 給應(yīng)用開發(fā)者提供了一套在多個(gè)設(shè)備不同應(yīng)用之間進(jìn)行任務(wù)流轉(zhuǎn)的API接口荷腊,實(shí)現(xiàn)設(shè)備協(xié)同需要關(guān)注 流轉(zhuǎn)任務(wù)管理服務(wù) 和 分布式任務(wù)調(diào)度。
? 流轉(zhuǎn)任務(wù)管理服務(wù):在流轉(zhuǎn)發(fā)起端急凰,接受用戶應(yīng)用程序注冊(cè)女仰,提供流轉(zhuǎn)入口、狀態(tài)顯示抡锈、退出流轉(zhuǎn)等管理能力疾忍。
? 分布式任務(wù)調(diào)度:提供遠(yuǎn)程服務(wù)啟動(dòng)、遠(yuǎn)程服務(wù)連接企孩、遠(yuǎn)程遷移等能力锭碳,并通過不同能力組合,支撐用戶應(yīng)用程序完成跨端遷移或多端協(xié)同的業(yè)務(wù)體驗(yàn)勿璃。
? 分布式安全:提供E2E的加密通道擒抛,為用戶應(yīng)用程序提供安全的跨端傳輸機(jī)制推汽,保證“正確的人,通過正確的設(shè)備歧沪,正確地使用數(shù)據(jù)”歹撒。
? 分布式軟總線:使用基于手機(jī)、平板诊胞、智能穿戴暖夭、智慧屏等分布式設(shè)備的統(tǒng)一通信基座,為設(shè)備之間的互聯(lián)互通提供統(tǒng)一的分布式通信能力撵孤。
? 任務(wù)流轉(zhuǎn)流程:設(shè)備A和設(shè)備B登錄相同的華為賬號(hào)迈着,在同一網(wǎng)絡(luò)下。設(shè)備A向設(shè)備B發(fā)起協(xié)同邪码,應(yīng)用程序需先向系統(tǒng)的流轉(zhuǎn)任務(wù)管理服務(wù) 注冊(cè)回調(diào)裕菠,獲取到設(shè)備B的 DeviceId 等設(shè)備信息,設(shè)備A初始化分布式任務(wù)調(diào)度闭专,通過設(shè)備DeviceId指定設(shè)備發(fā)起協(xié)同奴潘,設(shè)備B接收到協(xié)同請(qǐng)求,初始化分布式任務(wù)調(diào)度影钉,啟動(dòng)對(duì)應(yīng)的應(yīng)用程序画髓,把流轉(zhuǎn)的狀態(tài)上報(bào)給流轉(zhuǎn)任務(wù)管理服務(wù),流轉(zhuǎn)任務(wù)管理服務(wù)返回流轉(zhuǎn)結(jié)果平委,完成一次設(shè)備A到設(shè)備B的任務(wù)流轉(zhuǎn)奈虾。
理解分布式軟總線
? 分布式:指的是一種運(yùn)行方式,簡單來說就是任務(wù)可以在一個(gè)設(shè)備上運(yùn)行肆汹,也可以多個(gè)設(shè)備連接起來一起運(yùn)行愚墓,在多個(gè)設(shè)備中沒有一個(gè)絕對(duì)的中心。
? 總線:簡單了解一下“總線”的概念昂勉,在計(jì)算機(jī)系統(tǒng)中浪册,各個(gè)部件之間傳送信息的通道叫總線,外部設(shè)備通過相應(yīng)的接口與總線相連接岗照,組成了整個(gè)計(jì)算機(jī)系統(tǒng)村象。
? 分布式軟總線:所以不難理解分布式軟總線其實(shí)就是實(shí)現(xiàn)多個(gè)設(shè)備之間的連接,傳遞消息攒至,實(shí)現(xiàn)任務(wù)多端運(yùn)行的一種技術(shù)厚者。在HarmonyOS中,底層已經(jīng)幫我們實(shí)現(xiàn)了設(shè)備之間的組網(wǎng)迫吐、發(fā)現(xiàn)和連接库菲,所以并不需要關(guān)心設(shè)備怎么通信,只需要調(diào)用底層封裝好的接口志膀,實(shí)現(xiàn)多設(shè)備協(xié)同就可以了熙宇。
實(shí)現(xiàn)步驟
實(shí)現(xiàn)分布式多設(shè)備協(xié)同鳖擒,需要實(shí)現(xiàn)跨端啟動(dòng)應(yīng)用、后臺(tái)PA服務(wù)烫止、分布式數(shù)據(jù)同步的功能蒋荚,具體實(shí)現(xiàn)流程如下
一、跨設(shè)備啟動(dòng)應(yīng)用
多設(shè)備協(xié)同實(shí)現(xiàn)的前提馆蠕,需要在多端安裝相同的應(yīng)用期升,而在現(xiàn)實(shí)使用環(huán)境中,在多個(gè)設(shè)備中安裝一個(gè)相同的應(yīng)用還是一個(gè)比較麻煩的事互躬。而HarmonyOS的原子化服務(wù)則不需要用戶手動(dòng)安裝播赁,由系統(tǒng)程序框架后臺(tái)安裝后即可使用,在HarmonyOS的服務(wù)中心以服務(wù)卡片的形式展示吼渡。
應(yīng)用由原子化服務(wù)平臺(tái)(Huawei Ability Gallery)管理和分發(fā)行拢,只需要上傳到原子化服務(wù)平臺(tái)(Huawei Ability Gallery)即可,在多設(shè)備協(xié)同中诞吱,當(dāng)設(shè)備A的應(yīng)用向設(shè)備B的應(yīng)用發(fā)起多端協(xié)同,如果設(shè)備B上沒有安裝對(duì)應(yīng)服務(wù)竭缝,HarmonyOS會(huì)自動(dòng)下載相關(guān)原子化服務(wù)房维,和A端的應(yīng)用一起進(jìn)行多端協(xié)同。
跨設(shè)備啟動(dòng)應(yīng)用抬纸,也就是設(shè)備A上的應(yīng)用可以拉起設(shè)備B上的應(yīng)用咙俩。因?yàn)樵踊?wù)應(yīng)用免安裝的特性,所以不用關(guān)心應(yīng)用在多設(shè)備上的安裝湿故,只需實(shí)現(xiàn)跨設(shè)備啟動(dòng)應(yīng)用即可阿趁。
1. 創(chuàng)建原子化服務(wù)
以原子化服務(wù)的形式創(chuàng)建項(xiàng)目, 原子化服務(wù)的特點(diǎn)是支持免安裝坛猪,沒有應(yīng)用圖標(biāo)脖阵,只在 HarmanoyOS 服務(wù)中心以卡片的形式展現(xiàn),支持跨端遷移和多端協(xié)同墅茉。
在新建項(xiàng)目時(shí)選擇Atomic Service命黔,創(chuàng)建一個(gè)原子化服務(wù),同時(shí)打開Show in service center 開關(guān)就斤,自動(dòng)創(chuàng)建服務(wù)卡片悍募,去掉TV的勾選狀態(tài),目前服務(wù)卡片不支持TV設(shè)備洋机。
2. 創(chuàng)建HarmonyOS IDL接口
選擇項(xiàng)目的module目錄坠宴,點(diǎn)擊鼠標(biāo)右鍵,選擇New>Idl File绷旗,如下圖:
IDL是HarmonyOS的接口描述語言喜鼓,可以實(shí)現(xiàn)IPC跨進(jìn)程間通信副砍,接口的提供方是服務(wù)端,客戶端綁定應(yīng)用的服務(wù)來進(jìn)行交互颠通。
在IDL中定義服務(wù)端接口址晕,代碼如下。
登錄后復(fù)制
**interface** com.wealchen.multipoint.IMultiPointIdl {
*//啟動(dòng)服務(wù)*
void serviceStart([in] int code);
*//發(fā)送消息*
void sendMsg([in] int code,[in]int extras);
*//停止服務(wù)*
int serviceStop();
}
創(chuàng)建的IDL接口通過編譯會(huì)在build > generated > source > Idl> 目錄 debug 和release 下自動(dòng)生成對(duì)應(yīng)的接口類顿锰、樁類和代理類谨垃,如下圖。
3. 實(shí)現(xiàn)后臺(tái)接口服務(wù)
在HarmonyOS中硼控,客戶端綁定服務(wù)端后刘陶,獲取到序列化的IRemoteObject對(duì)象,通過IRemoteObject對(duì)象實(shí)現(xiàn)客戶端與服務(wù)端的通信牢撼,IRemoteObject在編譯生成的樁類和代理類中已經(jīng)完成了對(duì)象的創(chuàng)建和消息發(fā)送的實(shí)現(xiàn)匙隔,具體可查看上圖中自動(dòng)生成的代碼。
創(chuàng)建一個(gè)Service后臺(tái)服務(wù)MultiPointService熏版,提供給客戶端連接纷责,并實(shí)現(xiàn)IDL中定義的接口,在接口實(shí)現(xiàn)中啟動(dòng)FA頁面撼短,接收客戶端發(fā)送的消息再膳,具體代碼如下:
登錄后復(fù)制
**public** **class** MultiPointService **extends** Ability {
*// DESCRIPTOR 保持與 MultiPointIdlStub 和 MultiPointIdlProxy中的一致*
**private** static final String DESCRIPTOR = "com.wealchen.multipoint.IMultiPointIdl";
**private** static final String TAG = MultiPointService.class.getName();
@Override
**protected** void onStart(Intent intent) {
**super**.onStart(intent);
}
@Override
**protected** IRemoteObject onConnect(Intent intent) {
**return** **new** MultiPointRemoteObject(DESCRIPTOR);
}
**private** **class** MultiPointRemoteObject **extends** MultiPointIdlStub {
**public** MultiPointRemoteObject(String descriptor) {
**super**(descriptor);
}
@Override
**public** void serviceStart(int _code) **throws** RemoteException {
*//啟動(dòng)WebViewAbility頁面*
Intent intent = **new** Intent();
Operation operation = **new** Intent.OperationBuilder().withBundleName(getBundleName())
.withAbilityName(WebViewAbility.class.getName()).build();
intent.setOperation(operation);
intent.setParam(Constants.INTENT_STAR_PARAM, _code);
startAbility(intent);
LogUtil.debug(TAG, "serviceStart : start WebViewAbility " + _code);
}
@Override
**public** void sendMsg(int _code, int _extras) **throws** RemoteException {
LogUtil.debug(TAG, "sendMsg code: " + _code + " extras: " + _extras);
}
@Override
**public** int serviceStop() **throws** RemoteException {
**return** 0;
}
}
}
4. 實(shí)現(xiàn)跨端啟動(dòng)應(yīng)用
啟動(dòng)跨端應(yīng)用需指定設(shè)備的DeviceId,通過設(shè)備管理器DeviceManager曲横,可獲取到當(dāng)前同一網(wǎng)絡(luò)下所有不是待機(jī)狀態(tài)的設(shè)備喂柒,拿到DeviceId,DeviceName等設(shè)備信息禾嫉,具體代碼如下:
登錄后復(fù)制
*//獲取同一網(wǎng)絡(luò)下的設(shè)備*
List<DeviceInfo> deviceInfos = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
**if** (deviceInfos == **null** && deviceInfos.size() == 0) {
**return**;
}
**for** (int i = 0; i < deviceInfos.size(); i++) {
String devId = deviceInfos.get(i).getDeviceId();
String devName = deviceInfos.get(i).getDeviceName();
}
通過DeviceId可以與指定設(shè)備的后臺(tái)服務(wù)MultiPointService連接灾杰,實(shí)現(xiàn)長期交互,系統(tǒng)提供了connectAbility方法熙参,實(shí)現(xiàn)跨設(shè)備PA連接與斷開連接的能力艳吠,通過AbilitySlice的connectAbility接口跨設(shè)備連接到后臺(tái)服務(wù)MultiPointService,發(fā)送消息到指定設(shè)備孽椰,設(shè)備在接收到消息之后可以執(zhí)行相應(yīng)的任務(wù)讲竿,從而實(shí)現(xiàn)跨設(shè)備應(yīng)用任務(wù)的調(diào)度,連接服務(wù)實(shí)現(xiàn)代碼如下:
登錄后復(fù)制
*//啟動(dòng)遠(yuǎn)端設(shè)備的FA*
**private** void startAbilityFa(String devicesId, String event, int localExtras) {
Intent intent = **new** Intent();
Operation operation =
**new** Intent.OperationBuilder()
.withDeviceId(devicesId)
.withBundleName(getBundleName())
.withAbilityName(MultiPointService.class.getName())
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
intent.setOperation(operation);
boolean connectFlag = connectAbility(intent, **new** IAbilityConnection() {
@Override
**public** void onAbilityConnectDone(ElementName elementName, IRemoteObject remoteObject, int extra) {
LogUtil.debug(TAG, "onAbilityConnectDone extra:" + extra);
multiPointIdl = MultiPointIdlStub.asInterface(remoteObject);
**try** {
**if** (multiPointIdl != **null**) {
**switch** (event) {
**case** "serviceStart":
multiPointIdl.serviceStart(0);
**break**;
**case** "sendMsg":
multiPointIdl.sendMsg(1001, localExtras);
**break**;
}
}
} **catch** (RemoteException e) {
LogUtil.error(TAG, "connect successful,but have remote exception");
}
}
@Override
**public** void onAbilityDisconnectDone(ElementName elementName, int extra) {
LogUtil.debug(TAG, "extra " + extra + " elementName " + elementName.getAbilityName());
disconnectAbility(**this**);
}
});
**if** (connectFlag) {
Toast.toast(**this**, "transmit successful!", TOAST_DURATION);
} **else** {
Toast.toast(**this**, "transmit failed!Please try again later.", TOAST_DURATION);
}
}
二弄屡、多端設(shè)備協(xié)同
多設(shè)備協(xié)同可以實(shí)現(xiàn)對(duì)跨端設(shè)備的控制题禀,使用HarmonyOS的分布式數(shù)據(jù)服務(wù),不同設(shè)備之間的數(shù)據(jù)可以實(shí)時(shí)更新并顯示在界面上膀捷。
1. 分布式數(shù)據(jù)服務(wù)介紹
分布式數(shù)據(jù)服務(wù)是HarmonyOS為應(yīng)用程序提供不同設(shè)備間同步數(shù)據(jù)的能力迈嘹,通過使用分布式數(shù)據(jù)接口,應(yīng)用程序?qū)?shù)據(jù)保存到分布式數(shù)據(jù)庫中,不同設(shè)備之間可以通過分布式數(shù)據(jù)服務(wù)互相訪問秀仲,支持?jǐn)?shù)據(jù)在相同帳號(hào)的多端設(shè)備之間相互同步融痛。
HarmonyOS的分布式數(shù)據(jù)庫是一種NoSQL類型數(shù)據(jù)庫,其數(shù)據(jù)以鍵值對(duì)key-value的形式進(jìn)行組織神僵、索引和存儲(chǔ)雁刷,分布式數(shù)據(jù)服務(wù)包含五部分:
? 服務(wù)接口:提供專門的數(shù)據(jù)庫創(chuàng)建、數(shù)據(jù)訪問保礼、數(shù)據(jù)訂閱等接口給應(yīng)用程序調(diào)用沛励,接口支持KV數(shù)據(jù)模型,支持常用的數(shù)據(jù)類型炮障,同時(shí)確保接口的兼容性目派、易用性和可發(fā)布性。
? 服務(wù)組件:負(fù)責(zé)服務(wù)內(nèi)元數(shù)據(jù)管理胁赢、權(quán)限管理企蹭、加密管理、備份和恢復(fù)管理以及多用戶管理等智末、同時(shí)負(fù)責(zé)初始化底層分布式DB的存儲(chǔ)組件谅摄、同步組件和通信適配層。
? 存儲(chǔ)組件:負(fù)責(zé)數(shù)據(jù)的訪問系馆、數(shù)據(jù)的縮減螟凭、事務(wù)、快照它呀、數(shù)據(jù)庫加密,以及數(shù)據(jù)合并和沖突解決等特性棒厘。
? 同步組件:連結(jié)了存儲(chǔ)組件與通信組件纵穿,其目標(biāo)是保持在線設(shè)備間的數(shù)據(jù)庫數(shù)據(jù)一致性,包括將本地產(chǎn)生的未同步數(shù)據(jù)同步給其他設(shè)備奢人,接收來自其他設(shè)備發(fā)送過來的數(shù)據(jù)谓媒,并合并到本地設(shè)備中。
? 通信適配層:負(fù)責(zé)調(diào)用底層公共通信層的接口完成通信管道的創(chuàng)建何乎、連接句惯,接收設(shè)備上下線消息,維護(hù)已連接和斷開設(shè)備列表的元數(shù)據(jù)支救,同時(shí)將設(shè)備上下線信息發(fā)送給上層同步組件抢野,同步組件維護(hù)連接的設(shè)備列表,同步數(shù)據(jù)時(shí)根據(jù)該列表歼指,調(diào)用通信適配層的接口將數(shù)據(jù)封裝并發(fā)送給連接的設(shè)備伴箩。
2. 創(chuàng)建分布式數(shù)據(jù)庫
創(chuàng)建分布式數(shù)據(jù)庫管理器列牺,設(shè)置是否開啟加密带族,自動(dòng)同步功能恃轩,定義數(shù)據(jù)存儲(chǔ)和查詢方法结洼,使用手動(dòng)同步數(shù)據(jù)的方法實(shí)現(xiàn)數(shù)據(jù)的同步,詳細(xì)代碼代碼如下:
登錄后復(fù)制
**public** **class** MyKvStoreManager {
**private** static final String TAG = MyKvStoreManager.class.getName();
**private** static MyKvStoreManager instance = **null**;
**private** static SingleKvStore singleKvStore = **null**;
**private** static KvManager kvManager;
**private** MyKvStoreManager(Context context) {
createKVManager(context);
}
*/**
** 創(chuàng)建分布式數(shù)據(jù)管理器*
** \*/*
**public** static void createKVManager(Context context) {
KvManagerConfig config = **new** KvManagerConfig(context);
kvManager = KvManagerFactory.getInstance().createKvManager(config);
**try** {
Options options = **new** Options();
options.setCreateIfMissing(**true**)
.setAutoSync(**false**)
.setEncrypt(**false**)
.setKvStoreType(KvStoreType.SINGLE_VERSION);
String storeId = "remoteData";
singleKvStore = kvManager.getKvStore(options, storeId);
} **catch** (KvStoreException e) {
LogUtil.error(TAG, "getKvStore:" + e.getKvStoreErrorCode());
}
}
*/**
** 存儲(chǔ)數(shù)據(jù)*
** \*/*
**public** static void putKvStore(String key, String value) {
**if** (singleKvStore == **null**) {
**return**;
}
**try** {
singleKvStore.putString(key, value);
} **catch** (KvStoreException e) {
LogUtil.debug(TAG, "putString:" + e.getKvStoreErrorCode());
}
}
*/**
** 查詢數(shù)據(jù)*
** \*/*
**public** static String getKvStore(String key) {
String valueString = "";
**try** {
valueString = singleKvStore.getString(key);
} **catch** (KvStoreException e) {
LogUtil.debug(TAG, "getString:" + e.getKvStoreErrorCode());
}
**return** valueString;
}
*/**
** 手動(dòng)同步數(shù)據(jù)*
** \*/*
**public** static void syncData() {
List<DeviceInfo> deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER);
List<String> deviceIdList = **new** ArrayList<>();
**for** (DeviceInfo deviceInfo : deviceInfoList) {
deviceIdList.add(deviceInfo.getId());
LogUtil.debug(TAG,"syncData getId: "+deviceInfo.getId());
}
**if** (deviceIdList.isEmpty()){
**return**;
}
singleKvStore.sync(deviceIdList, SyncMode.PUSH_PULL);
}
*/**
** 訂閱數(shù)據(jù)同步結(jié)果*
** \*/*
**public** static void dataChangeObserver(KvStoreObserver storeObserver) {
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver);
}
}
3. 訂閱分布式數(shù)據(jù)變化
訂閱分布式數(shù)據(jù)變化客戶端應(yīng)用需要實(shí)現(xiàn)KvStoreObserver接口叉跛,KvStoreObserver接口回調(diào)中返回?cái)?shù)據(jù)更新的結(jié)果松忍,根據(jù)返回結(jié)果應(yīng)用執(zhí)行相應(yīng)的任務(wù),或者更新界面筷厘,從而實(shí)現(xiàn)多端設(shè)備的同步鸣峭,注意:回調(diào)方法中不允許更新UI組件等阻塞動(dòng)作。
更新UI可以通過getMainTaskDispatcher().asyncDispatch()切換到UI主線程更新UI的敞掘,詳細(xì)代碼如下:
登錄后復(fù)制
MyKvStoreManager.dataChangeObserver(**new** KvStoreObserver() {
@Override
**public** void onChange(ChangeNotification changeNotification) {
LogUtil.debug(TAG, "dataChangeObserver");
List<Entry> updateEntries = changeNotification.getUpdateEntries();
**for** (int i = 0; i < updateEntries.size(); i++) {
String key = updateEntries.get(i).getKey();
String value = updateEntries.get(i).getValue().getString();
LogUtil.debug(TAG, "dataChangeObserver key:" + key + " value:" + value);
getMainTaskDispatcher().asyncDispatch(**new** Runnable() {
@Override
**public** void run() {
**switch** (key) {
**case** JS_ADD_NAME:
*//添加名字*
setJsAddName(value);
**break**;
**case** JS_DEL_NAME:
*//刪除名字*
setJsDelName(value);
**break**;
**default**:
updateListView(key, value);
**break**;
}
}
});
}
}
});
三叽掘、WebView與JavaScript的交互
1. 在WebView調(diào)用H5頁面的JavaScript方法
更新H5頁面時(shí),WebView需要調(diào)用JavaScript玖雁,通過WebView.executeJs()傳入H5頁面中對(duì)應(yīng)的方法名稱更扁,實(shí)現(xiàn)應(yīng)用調(diào)用頁面內(nèi)的JavaScript方法,實(shí)現(xiàn)的代碼如下:
登錄后復(fù)制
**private** void setJsAddName(String addName) {
LogUtil.debug(TAG, "addName:" + addName);
String add_js = String.format("javascript:addName('%s')", addName);
webView.executeJs(add_js, **new** AsyncCallback<String>() {
@Override
**public** void onReceive(String msg) {
*// 在此確認(rèn)返回結(jié)果*
LogUtil.debug(TAG, "executeJs onReceive:" + msg);
}
});
}
H5頁面定義的方法:
**function** addName(name){
**var** tpl = document.getElementById('name').innerText
**var** str = name +'\n'
document.getElementById('name').innerText = tpl.concat(str)
**return** name
}
2. H5頁面調(diào)用應(yīng)用中的方法
WebView組件通過注入回調(diào)對(duì)象到頁面內(nèi)容赫冬,實(shí)現(xiàn)在H5頁面中調(diào)用應(yīng)用中的方法浓镜。
H5頁面調(diào)用應(yīng)用中的方法:
登錄后復(fù)制
**function** callToApp() {
**if** (window.showDeviceList && window.showDeviceList.call) {
**var** result = showDeviceList.call("showDeviceList");
}
}
應(yīng)用中定義的方法:
webView.addJsCallback("showDeviceList", **new** JsCallback() {
@Override
**public** String onCallback(String s) {
getMainTaskDispatcher().asyncDispatch(**new** Runnable() {
@Override
**public** void run() {
**switch** (s) {
**case** "showDeviceList":
**if** (!bottomDialog.isShowing()) {
bottomDialog.show();
}
**break**;
}
}
});
**return** method;
}
});
總結(jié)
應(yīng)用實(shí)現(xiàn)了包括原子化服務(wù)、任務(wù)流轉(zhuǎn)劲厌、跨端啟動(dòng)應(yīng)用膛薛、分布式數(shù)據(jù)服務(wù)、多端設(shè)備協(xié)同补鼻、WebView組件與JavaScript交互的功能哄啄,其中包含了HarmonyOS系統(tǒng)才具有的功能。以上只是簡單介紹了HarmonyOS特有功能的實(shí)現(xiàn)风范,當(dāng)然HarmonyOS的特性不止這些咨跌,更多的功能和實(shí)現(xiàn)還需要開發(fā)者去探索。