“萬物互聯”似乎是這些年被提的最多的一個概念,在我們的理解中萬物互聯似乎就是將生活中的每個實物都接入到網絡中。不過因為“萬物互聯”概念中,“造物”的廠商千千萬,各自接入網絡的方式又五花八門。所以在絕大部分情況下,即便萬物真能接入網絡,體驗也是割裂的。
華為的“萬物互聯”實現方式有些另辟蹊徑的意思:分布式技術通過“分布式軟總線”,將硬件資源融合為硬件池,不僅實現硬件互聯,而且讓硬件資源可以相互利用。典型比如WPS與華為終端分布式技術聯手打造的分布式文件,可以手機中的文檔,可以在PC上直接查看、編輯、保存,提升跨終端工作效率。
5月27日,華為在線上舉辦了一場HDD華為終端分布式生態技術交流會,除了華為自己針對這種分布式生態的技術講解和發展現狀,也拉來了不少第三方開發者講述接入生態的價值和過程。我們也期望通過這篇文章,面向開發者談談華為生態究竟是怎么回事,以及要加入生態,會不會特別麻煩。
分布式技術能做到什么?
我們借用一個具體的例子來看看,分布式技術究竟有哪些能力。科大訊飛的辦公本應該是比較早接入到華為分布式生態中的一類產品。主要解決的問題是跨設備傳輸文件,就是在手機和辦公本之間做筆記、網文、圖書等的分享。
而科大訊飛在智能辦公本中,期望解決的問題是:
- 辦公本不能拍照(受限于電子墨水屏的刷新率),那么利用手機的攝像頭,就能直接將筆記、教案拍攝存儲在辦公本里;
- 在手機上看到的各種網文、圖書可以方便地在辦公本上觀看;
- 當然,其中還有一些數據安全的考量,比如說用戶不希望把重要的筆記同步到互聯網上。
而在雙方合作后,華為終端分布式技術Share Kit便能夠解決這些問題,其采用華為私有傳輸協議,實現一鍵分享和更多的數據互通。在科大訊飛的辦公本上,其特性至少包括了快速發現設備;PAKE密鑰交換做到數據安全交換;快速信道能力協商,根據業務調整物理通路來實現高速傳輸。
在具體開發的Share Kit集成過程里,科大訊飛辦公本涉及到集成發送和接收功能,除了最上層Launcher集成Share Kit 接口,還需要在HAL(硬件抽象層)和framework層做一些適配。科大訊飛方面則表示,針對framework和HAL層,華為有提供代碼修改流程圖,可以非常輕松地搞定;而且即便集成階段遇到問題,華為也提供服務支持,可以共同解決問題。
對于很多硬件廠商來說,如果只需實現發送功能,那么整個開發過程會更簡單,只需上層Launcher集成Share Kit 接口即可。
分布式生態能力還在擴充
除了Share Kit外,CaaS Kit是另外一個典型的分布式Kit,比如接入了CaaSKit的無人機產品,可以直接在無人機APP應用內撥打暢連視頻通話,無人機鏡頭拍攝的畫面可直接作為視頻來源顯示在對方的屏幕上;Drift運動相機利用DeviceVirtualization Kit能力,可以在運動的時候發起暢連通話并將鏡頭一鍵轉移到Drift鏡頭,讓對方體驗第一運動視角帶來的緊張刺激;極米投影儀在集成Cast+Kit后,為用戶帶來流暢、高清的家庭娛樂投屏體驗。
在理解了華為的分布式生態究竟是什么,以及能做什么以后。接下來我們以其中的DeviceVirtualization Kit和Cast+Kit為例,簡單談談要將這些能力接入到自己的應用或設備中,具體過程和易用性如何,畢竟易用性是吸引開發者的一大重點。
從0 開始接入終端分布式
在前期準備階段,開發者需要在線提交申請,華為會把相應的SDK提供給開發者。開發可以選擇華為的DevEco Studio——這是一個全流程覆蓋的IDE。當前的beta版DevEco Studio需要在開發者聯盟做申請;也可以選擇Android Studio。
通過DevEco Studio的Kit Manager簡單勾選Kit、添加依賴庫之后,就進入開發階段了。
(1)DeviceVirtualization Kit
DeviceVirtualization Kit(以下簡稱DV Kit)能夠將附近的設備或組件轉換為手機的虛擬組件,將其能力作為手機的能力來使用。比如說外部的攝像頭、音箱、顯示器、話筒,甚至如心率傳感器這類設備組件,令其成為手機的眼睛、嘴巴、耳朵等等。
這里從應用開發者的角度來談一談接入過程。有關前期在開發者聯盟的注冊、獲取簽名證書指紋以及向華為方的接口權限申請這里不再贅述。這里著重說接入過程。首先是聲明虛擬外設的使用權限,以及聲明該應用調用DV Kit對應接口需要的權限,比如攝像頭、音頻、身體傳感器的權限等。申請不同的Android權限,在AndroidMenifest.xml文件中添加相應權限,例如:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="com.huawei.permission.DISTRIBUTED_VIRTUALDEVICE"/>
這里申請的是虛擬攝像頭、虛擬麥克風對應的Android權限;最后一行是在應用需要使用外部的虛擬分布式外設時,所需申請的權限。
DV Kit開發基本方法是,首先創建基礎DV Kit對象,并連接后端服務進行初始化;通過該對象獲取VirtualDeviceManager服務。通過VirtualDeviceManager服務可以發現當前手機能夠控制的虛擬設備。比如前文中的例子,VirtualDeviceManager服務發現Drift運動相機,并返回運動相機當前支持的是Camera(攝像頭)、Speaker(揚聲器)能力。
按照上圖思路,首先初始化連接DV Kit服務,服務初始化結果通過onConnect回調返回。連接成功后,調用getKitService獲取VirtualDeviceManager服務實例,用于控制虛擬設備:
//獲取DvKit對象并連接DvKit服務
DvKit.getInstance().connect(getApplicationContext(), new IDvKitConnectCallback() {
//服務連接成功后的回調通知
@Override
public void onConnect(int result) {
addLog("msdp service connect");
mVirtualDeviceManager = (VirtualDeviceManager) DvKit.getInstance().getKitService(VIRTUAL_DEVICE_CLASS);
mVirtualDeviceManager.subscribe(EnumSet.of(VIRTUALDEVICE), observer);
}
//服務斷開后的回調通知
@Override
public void onDisconnect() {
addLog("msdp service disconnect");
}
});
接下來就是設備發現,如前文所述連接成功,獲取到VirtualDeviceManager服務,應用就能調用VirtualDeviceManager服務的startDiscovery接口用于發現周圍的可用設備。發現的設備會通過IDiscoveryCallback回調的onFound接口返回:
//開始發現設備
mVirtualDeviceManager.startDiscovery(new IDiscoveryCallback() {
//設備發現時的回調接口
@Override
public void onFound(VirtualDevice device, int state) {
if (device == null) {
addLog("onDevice callback but device is null");
} else {
HwLog.d(TAG, "onDevice Found: " + Util.hideSensitiveInfo(device.getDeviceId()) + " Name: "
+ device.getDeviceName() + " Type:" + device.getDeviceType());
if (!mVirtualDeviceMap.containsKey(device.getDeviceId())) {
addLog("onDevice Found: " + device.getDeviceId() + " Name: " + device.getDeviceName() + " Type:"
+ device.getDeviceType());
mVirtualDeviceMap.put(device.getDeviceId(), device);
handler.sendMessage(handler.obtainMessage(DEVICE_ADD, device));
}
}
}
//發現狀態變更的回調通知
@Override
public void onState(int state) {
}
});
在發現虛擬設備之后,應用就可以調用虛擬設備的getDeviceCapability()接口獲取設備支持能力,按需選擇具體的能力。具體是調用enableVirtualDevice來使能所需使能的設備和能力,支持同時傳入多個能力。應用使能的結果可以通過subscribe接口傳入的回調對象來獲得:
mVirtualDeviceManager.enableVirtualDevice(deviceId, EnumSet.of(CAMARA), null);
//調用subscribe時傳入的observer對象
private IVirtualDeviceObserver observer = new IVirtualDeviceObserver() {
//虛擬設備狀態變化時的回調通知
@Override
public void onDeviceStateChange(VirtualDevicevirtualDevice, intreturncode) {
}
//虛擬設備能力狀態變化時的回調通知
@Override
public void onDeviceCapabilityStateChange(VirtualDevicevirtualDevice, Capability capability, intreturncode) {
if (returncode == EventType.EVENT_DEVICE_CAPABILITY_ENABLE) {
//當設備能力使能成功時,應用處理使能成功流程
onEnable(virtualDevice, capability);
} else if (returncode == EventType.EVENT_DEVICE_CAPABILITY_DISABLE) {
//當設備能力去使能成功時,應用處理去使能成功流程
onDisable(virtualDevice, capability);
} else {
//當虛擬設備能力狀態異常時,應用應處理異常流程
onError(virtualDevice, capability, returncode);
}
}
};
這里是以虛擬Camera能力為例,在虛擬Camera能力接入后,應用可以通過getData接口來獲取虛擬設備(比如Drift運動相機)的虛擬Camera id。應用隨后就能和傳統獲取手機的本地前后置攝像頭一樣,來獲取虛擬Camera的屬性信息(getCameraCharacteristics),以及打開虛擬Camera(openCamera),示例如下:
//通過虛擬設備的getData接口獲取設備虛擬Camera的ID
String cameraId = device.getData(Constants.ANDROID_CAMERAID_FRONT);
//使用CameraManager的getCameraCharacteristics接口獲取虛擬Camera的屬性信息
CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
//使用CameraManager的openCamera接口打開虛擬Camera
manager.openCamera(cameraId, mStateCallback, null)
“去使能”是通過調用disableVirtualDevice接口來實現的,比如去使能攝像頭能力:
mVirtualDeviceManager.disableVirtualDevice(deviceId, EnumSet.of(CAMERA));
整體DV Kit提供服務的斷連,釋放底層資源:
DvKit.getInstance().disConnect();
另外各種應用的具體實現也各有不同,例如有些可能需要使用虛擬Display,有些則需要虛擬Sensor(如Drift Life應用),或者使用本地消息通知等。這在華為開發者文檔中都有比較詳細的介紹,這里不再一一列舉。
整個過程還是比較清晰和便捷的,對于一般開發者而言,代碼難度也不高;其流程對于App開發的整體業務存在的影響實際上都是比較小的,這是融入分布式生態比較便利的體現。
(2)Cast+ Kit
在日常生活中,我們經常需要投屏玩游戲、看電影等方式實現跨屏幕協同。而一些第三方廠商,如極米就有多款投影儀集成了華為終端分布式技術Cast+ Kit。從現場演示來看,令人印象比較深刻的就是低延遲,這對于投屏玩游戲還是相對重要的。
Cast+Kit在設備側需要與華為進行合作協議簽署后獲取。對于設備側而言,開發過程首先也是申請權限,包括允許訪問網絡連接、獲取當前WiFi接入狀態和熱點信息、獲取設備當前WiFi頻率信息等。
上面這張圖給出了簡略的調用流程。其大步驟分成了:首先做變量聲明和實例獲取:
private PlayerClientmPlayerClient;
private ProjectionDevicemProjectionDevice;
//獲取PlayerClient實例
mPlayerClient = PlayerClient.getInstance();
啟動服務并注冊監聽:實現IEventListener.Stub()
private IEventListenermCallback = new IEventListener.Stub() {
//上報連接狀態。
public booleanonEvent(inteventId, String type) {
//根據連接狀態進行對應的配置及邏輯處理。
…
return true;
}
//上報顯示相關事件。
public booleanonDisplayEvent(inteventId, DisplayInfodisplayInfo) {
//根據連接狀態進行對應的配置及邏輯處理。
…
return true;
}
};
啟動服務:
mPlayerClient.init(context);
注冊回調接口:
mPlayerClient.registerCallback(mCallback);
隨后進行投屏業務相關設置,設置鑒權模式信息:
AuthInfoauthInfo = null;
if (needPassword) {
//密碼模式,設置6位密碼(需要支持混合密碼的能力)
authInfo = new AuthInfo(AuthInfo.AUTH_MODE_PWD);
authInfo.setAuthCode(password);
} else {
//PIN碼模式
authInfo = new AuthInfo(AuthInfo.AUTH_MODE_GENERIC);
}
booleanisAuthModeSuccessfullySet = mPlayerClient.setAuthMode(authInfo);
If (isAuthModeSuccessfullySet) {
//更新本地密碼 or 更新UI
}
設置大屏端設備的投屏能力,首先構造HiSightCapability對象:
HiSightCapability capability = new HiSightCapability(1920, 1080, 1920, 1080);
設置投屏顯示幀率,默認為30fps:
capability.setVideoFps(30);
根據平臺配置低時延策略:
capability.setMediaCodecConfigureFlag(2)
設置投屏能力:
mPlayerClient.setCapability(capability);
根據選用芯片的不同,可選用HiSightCapability提供的不同方法,設定平臺的解碼優化參數:
HiSightCapability.setMediaCodecConfigureFlag(int flag)
HiSightCapability. setMediaFormatInteger(String name, int value)
HiSightCapability. setMediaFormatFloat(String name, float value)
HiSightCapability. setMediaFormatLong(String name, long value)
HiSightCapability. setMediaFormatString(String name, String value)
配置大屏端設備信息,包括大屏端設備名稱、設備類型:
private DeviceInfomDeviceInfo = new DeviceInfo(mTvDeviceName, DeviceInfo. TYPE_TV);
并設置設備可被周圍的設備發現:
mPlayerClient.setDiscoverable(true, mDeviceInfo);
在大屏設備首次收到移動端連接請求后,會上報EVENT_ID_PIN_CODE_SHOW信息,并提供對端設備信息。在首次連接成功后,再次通過PIN碼模式發起連接請求時,會跳出PIN碼鑒權步驟:
if (displayInfo != null) {
//設備連接需要的PIN碼
String pinCode = displayInfo.getPinCode();
//按照UX規范開發PIN碼界面以展示PIN碼
showPinCode(pinCode, mProjectionDevice.getDeviceName());
//設置允許手機連接(用于不彈框讓用戶選擇的場景)
mPlayerClient.setConnectRequestChooseResult(new ConnectRequestChoice(
Constant.CONNECT_REQ_CHOICE_ALWAYS, mProjectionDevice));
}
在手機正確輸入PIN碼鑒權通過后,大屏端應用會上報EVENT_ID_CONNECT_REQ信息,另外也包含移動端設備信息:
if (displayInfo != null) {
//獲取請求連接的移動端設備信息
mProjectionDevice = displayInfo.getProjectionDevice();
}
在EVENT_ID_CONNECT_REQ之后,會順序上報EVENT_ID_DEVICE_CONNECTED和EVENT_ID_PAUSED消息。PAUSED消息下,大屏端可以設置Surface并開始播放投屏視頻流,為加快起播速度,也可提前(如EVENT_ID_CONNECT_REQ消息下)啟動投屏Acitivity和Surface的創建。
mProjectionDevice為Event_ID_CONNECT_REQ消息中從DisplayInfo中獲取的對端設備信息,可通過其獲取DeviceId,再通過DeviceID構造TrackControl對象做投屏使用。投屏成功,大屏端將上報EVENT_ID_CASTING消息,標識當前正在投屏。
具體實現上,首先設計應用投屏界面XML布局:
<com.huawei.castpluskit.HiSightSurfaceView
android:id="@+id/HiSightSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
另外應用層面,要求保證投屏過程中不能錄屏、截屏、錄音:
mHiView.setSecure(true);
再添加SurfaceHolder的回調,在surfaceCreated監聽中設置投屏控件
SurfaceHoldersurfaceHolder = mHiView.getHolder();
surfaceHolder.addCallback(mSurfaceHolderCallback);
private SurfaceHolder.CallbackmSurfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
isSurfaceReady = true;
if(isReceivePaused) {
mPlayerClient.setHiSightSurface(mHiView.getHolder().getSurface());
}
}
}
最后開始投屏:
mPlayerClient.play(new TrackControl(mProjectionDevice.getDeviceId()));
斷開連接:
mPlayerClient.disconnectDevice(mProjectionDevice);
對絕大部分開發者而言,這都是一個相當簡單快速的集成過程。從這些開發者的代碼不難發現,華為在Kit以及系統層面,為簡化開發難度,還是花了不少心思的。而對用戶來說,投屏質量和效率都是能夠得到保證的,用戶不需要安裝app,也沒有復雜操作;而且延遲各方面的體驗也都在同類的無線投屏方案中顯得比較靠譜——這些也是開發者不需要關心的。
從DevEco Studio看華為的開發生態
針對開發流程,最后再談談目前仍處在beta階段的DevEco Studio工具。如前文所述這就是個來自華為的IDE,整體是為華為的全場景智慧化戰略設想所做的。面向的當然包括了應用開發和設備開發,內部集成了華為的分布式能力。
完整的DevEco Studio是基于Intellij開源代碼,加上華為的開放能力支持。另外華為也基于Android Studio做了DevEco Toolkit插件,作為另一種形態提供給開發者使用。
DevEco Studio的某些特性,本身也是在為分布式生態構建提供便利,這是在分布式能力接入本身就比較簡單的情況下,所做的一些加分項。比如說:
前文就提到的,DevEco Studio針對這些分布式能力有集中管理和呈現的方案,開發者可以直接查看、管理這些Kit,并且在有需要時通過勾選就將某個Kit融入到開發中;甚至還能進行Kit的一鍵升級操作。這很大程度上提供了開發的便利性。
另外,所謂的“拖拽式生成API代碼”,即調用API功能的代碼樣例可以直接拖動到代碼編輯區。若樣例代碼依賴某些特殊的包,則在拖動操作后,會自動引入依賴包、自動生成頭部import。這些都還是頗具特色的。
在開發周期的調測方面,華為提供了遠程真機,大概有5000多個華為機型,不同的系統版本、屏幕分辨率等可做調測。與此同時,華為另外還提供了云測和DFX診斷服務、“非侵入式”的數據分析。
不言而喻,降低開發難度——不管是完善IDE的體驗,還是降低接入Kit的技術難度——本質上都是為了吸引更多的開發者加入到這個生態中來。現階段是華為1+8+N生態的擴展期,華為期望構建起的是以智能手機為中心,將所有周邊智能設備通過分布式能力串聯起來的生態。這是華為在萬物互聯方面的龐大視野,也是華為對萬物互聯樣貌的理解。
這樣的布局,顯然打破了智能手機自身生態的局限,也并不局限在單純的智能家居或者某種具體使用場景,描繪的是一幅令IoT真正構成統一生態的圖景。現如今華為側打造了這一生態的基礎或平臺,并正逐步補足和完善;而要讓生態真正活躍、豐富起來,仍然要靠三方開發者的共同努力,這是值得期待的。