背景
隨着鴻蒙2.0的發佈,華爲部分手機用戶迎來鴻蒙時代,京東做爲華爲鴻蒙OS的合做APP,首次投入鴻蒙應用商用版開發,目前已上架V10.0.2版本。java
鴻蒙OS特性
2021年6月3日,華爲舉行了鴻蒙OS2.0發佈會。鴻蒙OS帶來了全新桌面及用戶體驗,如桌面圖標支持上滑呼出快捷卡片,原子化能力能經過鴻蒙設備間流轉實現快速分享、顯示,以及統一控制中心(手勢:右上角下滑)、服務中心(手勢:屏幕左下角或右下角向側上方滑動)等。android
Android工程鴻蒙化
01背景
爲了利用上鴻蒙的特性,咱們開發者須要儘快的將App鴻蒙化。可是將整個App鴻蒙化的工做量是特別龐大的,那麼有沒有一種方式既能利用鴻蒙的特性也能快速適配呢,答案是有的,那就是混合包開發模式,整個App基本上沒有大的修改,只須要新增鴻蒙相關模塊用來實現鴻蒙相關特性便可。京東App-鴻蒙版可以作到快速適配上線,並擁有鴻蒙特性,就是利用了這種開發模式。下面咱們將以京東App-鴻蒙版爲例,具體介紹下相關流程。shell
02Android工程改造
咱們須要依賴鴻蒙的一個兼容包(包文件能夠聯繫咱們取得),將咱們現有的Application繼承自HarmonyApplication,僅需編譯依賴,不須要真正打進App中。json
compileOnly files('libs/abilityshell_ide_java.jar')
2. 在AndroidManifest.xml中,向根節點下增長。網絡
<uses-feature android:name="zidane.software.ability" android:required="false" />
3. 向application節點下新增子節點。app
<meta-data android:name="permZA" android:value="true" /> <meta-data android:name="multiFrameworkBundle" android:value="true" />
自此已經能夠構建出鴻蒙須要的apk包了,你們也能夠經過配置編譯變體等形式,構建鴻蒙版本的apk包。iview
注意:鴻蒙包中混入的apk必需要是64位的。分佈式
03配置鴻蒙工程
1.在鴻蒙工程中entry module中的build.gradle裏,增長混入apk文件配置。ide
legacyApkOptions{ legacyApk rootProject.file('android_entry.apk').absolutePath //混入apk的存放路徑 signConfig{ storeFile rootProject.file('xxx.keystore') //混入apk所用簽名文件 } }
總體配置以下圖 :工具
2. 簽名改造,咱們須要根據Android apk的簽名來作鴻蒙應用簽名的申請,須要將.keystore或.jks格式的簽名文件轉換成.p12文件,簽名祕鑰和別名保持不變。具體轉換步驟,你們能夠自行搜索。
參考:在轉換.p12文件時,咱們遇到了問題,因爲咱們Android的簽名格式是.keystore,轉出來的.p12文件有問題沒法申請鴻蒙應用證書,通過和華爲方面溝通,咱們將鴻蒙應用的簽名祕鑰和別名保持和Android的一致,解決了打包問題。
3. 配置文件增長屬性,在鴻蒙工程的每一個feature module的config.json app節點下,增長originalName,表示混入的apk包名,同時要將bundleName的值也改爲一致。
4. 在entry模塊下,新建一個空的Ability類並配置在config.json裏做爲啓動入口,如:
"abilities": [{ "skills": [{ "entities": ["entity.system.home"], "actions": ["action.system.home"] }], "orientation": "portrait", "visible": true, "name": "com.xxx.xxx.xx.EntryAbility", "icon": "$media:icon", "description": "$string:mainability_description", "label": "$string:app_name", "type": "page", "launchType": "standard" }],
自此已經能夠構建出包含原有Android功能的鴻蒙包了。
Android-鴻蒙互調用
01從Android啓動鴻蒙組件
咱們須要集成鴻蒙的一個jar包(能夠聯繫咱們得到此文件),來實現從Android啓動鴻蒙的組件。如:
Intent intent = new Intent();ComponentName componentName = new ComponentName("your harmony app's bundleName name","your ability's full name");intent.setComponent(componentName);intent.putExtras(bundle);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);AbilityUtils.startAbility(context, intent);
02鴻蒙模塊調用Android
1. 鴻蒙啓動Android組件
鴻蒙裏自己是支持啓動Android組件的,只須要在Intent裏增長一個flag
Intent.FLAG_NOT_OHOS_COMPONENT
如:
Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withDeviceId("") .withBundleName("your android app’s packagename") .withAbilityName("your android app’s activity fullname") .withFlags(Intent.FLAG_NOT_OHOS_COMPONENT) .build(); intent.setOperation(operation); startAbility(intent);
2. 鴻蒙模塊調用Android現有能力
在Android包裏,已經有了不少現有功能,如埋點收集、用戶登陸態獲取、定位、地址等等,在鴻蒙模塊裏須要用到這些功能時,咱們爲了節省時間暫時沒有再去開發一遍鴻蒙版,咱們利用了Java的反射技術來搞定。通過驗證,在Android中反射鴻蒙以及鴻蒙中反射Android都是能夠的。
03獲取當前是否爲鴻蒙系統
在有些場景下,咱們須要知道當前系統的運行環境是否是鴻蒙系統,可使用如下代碼段來實現。
private static final String HARMONY_OS = "harmony";/*** check the system is harmony os** @return true if it is harmony os*/public static boolean isHarmonyOS() { try { Class clz = Class.forName("com.huawei.system.BuildEx"); Method method = clz.getMethod("getOsBrand"); return HARMONY_OS.equals(method.invoke(clz)); } catch (ClassNotFoundException e) { Log.e(TAG, "occured ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e(TAG, "occured NoSuchMethodException"); } catch (Exception e) { Log.e(TAG, "occur other problem"); } return false;}
鴻蒙OS特性+購物應用場景開發
鴻蒙OS打破了設備間的壁壘,對用戶及應用開發者來講,造成了超級終端。超級終端包含手機、大屏、平板,將來或許會有更多的設備加入,設備間協同合做讓購物體驗變得優質。每一個設備再也不是孤立的個體,而是基於鴻蒙操做系統的智慧終端,即使用戶拿着不一樣的設備,也能夠有很好的體驗。經過一鍵流轉實現跨設備間的數據傳輸,從而實現無縫的購物體驗。
01流轉:直播間FA
介紹
流轉泛指多設備間的分佈式操做,打破設備界限,多設備聯動,使用戶應用程序可分可合、可流轉。流轉按照體驗可分爲跨端遷移和多端協同。流轉支持免安裝運行FA。京東App-鴻蒙版本中的直播FA就利用了流轉能力,將當前手機的直播流轉至TV端,作到無縫銜接,並支持經過手機端控制TV端直播顯示的功能。效果以下:
開發
咱們以京東App-鴻蒙版中直播FA的流轉開發經驗進行介紹,如何具有流轉能力。
1.權限要求
因爲使用到了分佈式能力,咱們須要先把權限配置好,在對應的module的config.json下,增長如下權限:
ohos.permission.GET_DISTRIBUTED_DEVICE_INFOohos.permission.DISTRIBUTED_DATASYNCohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE
同時在Ability裏,須要增長動態權限申請。
requestPermissionsFromUser( new String[]{SystemPermission.DISTRIBUTED_DATASYNC}, Constants.PermissionCode.PERMISSION_DISTRIBUTED_DATASYNC);
2.關鍵接口
3.功能實現
a. 經過流轉服務註冊管理器,將當前FA註冊,註冊時能夠指定流轉的過濾條件,如設備類型、目標設備等等:
b. 當須要流轉時,咱們經過流轉服務註冊管理器獲取當前知足條件的設備列表:
系統會自動查找設備,將知足條件的設備自動展現出來供用戶選擇,當用戶點擊某個設備後,就會回調IContinuationDeviceCallback的onDeviceConnectDone方法,獲取到目標設備的Id後,就能夠啓動目標設備的FA。
c. 啓動遠程FA
須要注意的是,在啓動對端設備上FA時,咱們要確保對端設備的分佈式能力已經被初始化。
02FA近場分享:商詳FA
介紹
FA近場分享能力依賴於華爲分享服務,能夠快速實現FA分享的功能。較單純的使用分佈式FA流轉功能,爲開發者免除了設備發現功能,而且沒有了同帳號同網絡等限制條件。在京東App-鴻蒙版中,商詳FA就使用了此功能實現了FA的近場分享,而且可以作到免安裝打開商詳頁面。下圖分別是A向B發送商詳FA 和 B接收商詳FA。
開發
咱們將以在京東App-鴻蒙版中的相關開發經驗介紹下如何進行FA近場分享的開發。
工做原理圖示:
因爲功能依賴華爲分享服務,咱們首先要引入IDL文件。
1. 導入IDL文件
在商詳FA module中java同級目錄,建立idl目錄,並建立包名com.huawei.hwshare.third,在此包名下建立IHwShareCallback.idl和 IHwShareService.idl文件,文件具體內容以下:
IHwShareCallback.idl:interface com.huawei.hwshare.third.IHwShareCallback {
[oneway] void notifyState([in] int state);
}IHwShareService.idl:sequenceable ohos.interwork.utils.PacMapEx;
interface com.huawei.hwshare.third.IHwShareCallback;
interface com.huawei.hwshare.third.IHwShareService {
int startAuth([in] String appId, [in] IHwShareCallback callback); int shareFaInfo([in] PacMapEx pacMapEx);
}
2. 對分享能力進行封裝
如下是咱們在商詳FA中封裝好的代碼,你們能夠直接使用。
package com.xxx.xxx.xxx;import com.huawei.hwshare.third.HwShareCallbackStub;import com.huawei.hwshare.third.HwShareServiceProxy;import ohos.aafwk.ability.IAbilityConnection;import ohos.aafwk.content.Intent;import ohos.app.Context;import ohos.bundle.ElementName;import ohos.eventhandler.EventHandler;import ohos.eventhandler.EventRunner;import ohos.interwork.utils.PacMapEx;import ohos.rpc.IRemoteObject;import ohos.rpc.RemoteException;import ohos.hiviewdfx.HiLog;import ohos.hiviewdfx.HiLogLabel;public class ShareFaManager { private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, "ShareFa"); private static final String LOG_FORMAT = "%{public}s: %{public}s"; // FA的圖標 byte[] len < 32768 非必須,不傳默認取應用圖標 public static final String HM_FA_ICON = "ohos_fa_icon"; // FA的名字 String len < 1024 非必須,不傳默認取應用名 public static final String HM_FA_NAME = "ohos_fa_name"; // ability類名 String len < 1024 必須 public static final String HM_ABILITY_NAME = "ohos_ability_name"; // 包名 String len < 1024 必須 public static final String HM_BUNDLE_NAME = "ohos_bundle_name"; // FA類型 int 暫時只有0 非必須,默認爲0 public static final String SHARING_FA_TYPE = "sharing_fa_type"; // FA卡片展現圖 byte[] len < 153600 必須 public static final String SHARING_THUMB_DATA = "sharing_fa_thumb_data"; // FA卡片展現信息 String len < 1024 必須 public static final String SHARING_CONTENT_INFO = "sharing_fa_content_info"; // 攜帶的額外信息,可帶到被拉起的FA String len < 10240 非必須 public static final String SHARING_EXTRA_INFO = "sharing_fa_extra_info"; private static final String TAG = "ShareHmFaManager"; private static final String SHARE_PKG_NAME = "com.huawei.android.instantshare"; private static final String SHARE_ACTION = "com.huawei.instantshare.action.THIRD_SHARE"; private static final long UNBIND_TIME = 20*1000L; private Context mContext; private String mAppId; private PacMapEx mSharePacMap; private static ShareFaManager sSingleInstance; private HwShareServiceProxy mShareService; private boolean mHasPermission = false; private EventHandler mHandler = new EventHandler(EventRunner.getMainEventRunner()); //服務綁定回調 private final IAbilityConnection mConnection = new IAbilityConnection() { @Override public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) { HiLog.error(LABEL_LOG, LOG_FORMAT, TAG, "onAbilityConnectDone success."); mHandler.postTask(()->{ mShareService = new HwShareServiceProxy(iRemoteObject); try { //華爲分享認證受權 mShareService.startAuth(mAppId, mFaCallback); } catch (RemoteException e) { HiLog.error(LABEL_LOG, LOG_FORMAT, TAG, "startAuth error."); } }); } @Override public void onAbilityDisconnectDone(ElementName elementName, int i) { HiLog.info(LABEL_LOG, LOG_FORMAT, TAG, "onAbilityDisconnectDone."); mHandler.postTask(()->{ mShareService = null; mHasPermission = false; }); } }; private Runnable mTask = () -> { if (mContext != null && mShareService != null) { mContext.disconnectAbility(mConnection); mHasPermission = false; mShareService = null; } }; //華爲分享認證受權回調 private final HwShareCallbackStub mFaCallback = new HwShareCallbackStub("HwShareCallbackStub") { @Override public void notifyState(int state) throws RemoteException { mHandler.postTask(()->{ HiLog.info(LABEL_LOG, LOG_FORMAT, TAG, "notifyState: " + state); if (state == 0) { mHasPermission = true; if (mSharePacMap != null) { shareFaInfo(); } } }); } }; /** \* 單例模式獲取ShareFaManager的實例對象 * \* @param context 程序Context \* @return ShareFaManager實例對象 */ public static synchronized ShareFaManager getInstance(Context context) { if (sSingleInstance == null && context != null) { sSingleInstance = new ShareFaManager(context.getApplicationContext()); } return sSingleInstance; } private ShareFaManager(Context context) { mContext = context; } private void shareFaInfo() { if (mShareService == null) { return; } if (mHasPermission) { HiLog.info(LABEL_LOG, LOG_FORMAT, TAG, "start shareFaInfo."); try { mShareService.shareFaInfo(mSharePacMap); mSharePacMap = null; } catch (RemoteException e) { HiLog.error(LABEL_LOG, LOG_FORMAT, TAG, "shareFaInfo error."); } } // 不使用時斷開 mHandler.postTask(mTask, UNBIND_TIME); } /** \* 開始分享 * \* @param appId 開發者聯盟網站建立鴻蒙服務/鴻蒙應用時生成的appid \* @param pacMap 服務信息載體 */ public void shareFaInfo(String appId, PacMapEx pacMap) { if (mContext == null) { return; } mAppId = appId; mSharePacMap = pacMap; mHandler.removeTask(mTask); shareFaInfo(); bindShareService(); } /** \* 綁定華爲分享服務 */ private void bindShareService() { if (mShareService != null) { return; } HiLog.error(LABEL_LOG, LOG_FORMAT, TAG, "start bindShareService."); Intent intent = new Intent(); intent.setBundle(SHARE_PKG_NAME); intent.setAction(SHARE_ACTION); intent.setFlags(Intent.FLAG_NOT_OHOS_COMPONENT); mContext.connectAbility(intent, mConnection); } }
3.開始分享
咱們將參數進行組裝,調用ShareFaManager的shareFaInfo方法便可自動的完成FA分享功能。如咱們將商詳FA進行分享:
注意:
1. 使用時要主要傳遞的數據不要超過限定的大小,不然會分享失敗並致使程序崩潰。
2. 在對端接收到分享後,咱們須要將自定義的參數取出來,從Intent中取sharing_fa_extra_info便可。
Ps:針對遠距離的場景,華爲也給出瞭解決方案,經過暢連便可分享購物連接。值得注意的是,此時好友還能夠經過屏幕共享在商品頁面進行塗鴉互動。
03服務卡片:搜索卡片
用戶上滑 App 圖標便可生成萬能卡片 ,在桌面呈現更豐富的信息,卡片信息支持實時更新,減小了 App 加載的時間,如目前京東app,用戶上滑 App 圖標可打開快捷搜索入口。
介紹
FA卡片是FeatureAbility的Page模板的一種界面展現形式。FA卡片經常使用於嵌入到其餘應用中做爲其界面的一部分顯示,並支持基礎的交互功能。卡片使用方做爲卡片展現的宿主負責顯示卡片,卡片使用方的典型應用就是桌面應用。卡片使用方僅限系統應用。
當FA規格小於10M時,能夠支持免安裝運行。系統最大支持500個卡片,相同名稱的卡片實例最大是32個。
經過服務卡片的一些特色,如定時更新、免安裝運行等,能夠很好的進行快捷入口的引導。如咱們能夠在卡片上展現活動商品,並按期更新,用戶能夠免安裝的打開活動詳情,當用戶產生進一步購買慾望時,用戶可下載整個App進行下單。
開發
卡片的開發支持JS和Java兩種方式。在京東App-鴻蒙版中的搜索FA裏,咱們加入了FA卡片,能夠直達搜索。下面咱們將以此爲例進行開發步驟的講解。
1.卡片配置
首先要在搜索FA的config.json中配置forms節點,好比:
咱們給SearchAbility節點下添加forms節點,就表示這個卡片的建立及管理由SearchAbility來負責。
注意:必需要設置label屬性,必須是資源形式的且不能是包名。
屬性解釋:
2. 實現卡片相關回調
在SearchAbility中,複寫如下幾個方法:
建立:在建立卡片時,咱們能夠從Intent中獲取當前要建立卡片的Id,如:
這是一個很簡單的卡片,咱們沒有對卡片中的視圖設置任何數據和事件,那麼點擊卡片後,打開的就是負責管理卡片的Ability。若是須要設置數據和事件,可使用如下方式
1. 建立ComponentProvider;
2. 經過ComponentProvider設置對應View的數據,以及點擊事件,目前可以支持的事件有START_ABILITY和START_SERVICE兩類;
3. 將ComponentProvider對象合併入ProviderFormInfo中。
更新:當觸發了更新卡片方法時,咱們能夠進行數據更新,並將最新的數據更新到卡片View上。
刪除:當卡片使用方將卡片刪除,咱們可能須要將對應卡片在App內的相關持久化數據進行刪除。
3.配置EntryCard目錄
配置EntryCard目錄,以便讓系統可以識別出服務卡片,並展現在服務中心的推薦裏。新建應用時能夠勾選自動生成,若是是以前IDE建立的工程,則須要手動補充上。
1)在工程根目錄下建立EntryCard目錄;
2) EntryCard目錄下,建立一個文件夾,取名爲擁有卡片的FA工程名,如咱們的搜索FA擁有服務卡片,搜索FA的工程名叫searchfeature,那咱們就建立一個文件夾,名字就叫作searchfeature;
3)在searchfeature目錄下建立base/snapshot兩級目錄,在其中放置咱們的卡片圖片,其命名方式爲formname-dimensions,如搜索卡片的卡片名稱配置的是search_card,尺寸是2*2的,那麼這個圖片就命名爲search_card-2x2.png。
鴻蒙App打包及上架
01打包構建
經過以上配置,咱們已經能夠進行鴻蒙App的構建了。目前鴻蒙App分爲兩種構建形式,debug和release,能夠經過DevEco工具自帶的編譯任務或者使用gradle的assembleDebug signReleaseApp任務進行構建。
其中debug模式構建方式出來的產物是多個目標設備的多個.hap文件,每一個FA都會構建出各自的.hap文件;release會構建出一個.app文件,咱們須要將此文件進行上架發佈。
安裝及運行
1. 開發者沒法安裝.app安裝包,此文件只能用於上架應用市場。
2. 經過adb shell bm get -udid獲取設備UDID後,錄入到開發者中心,並生成證書文件,咱們就能夠安裝.hap包。
3. 安裝時能夠將文件push到手機某個目錄下(如sdcard/hmphone),而後使用adb shell bm install -p /sdcard/hmphone/進行安裝,每次安裝能夠先刪除以前文件。
注意:因爲咱們沒法安裝驗證.app包,咱們要保證在debug和release兩種構建模式下,咱們的代碼不會發生改變。
02應用上架及發佈
1.若是尚未在開發者中心建立鴻蒙應用的話,須要先新增一個鴻蒙應用,包名和以前Android的包名保持一致,並關聯到同一個項目中。
2. 選擇咱們建立的鴻蒙應用,在【應用信息】頁面中,將應用安裝與升級修改成以下圖所示。
3. 在【版本信息】頁面中,點擊【版本/升級】建立新版本,在新版本頁面中的【軟件版本】模塊下,上傳咱們構建的.app軟件包後並勾選,在當前頁面填入相關信息後便可提交審覈,待審覈經過後,在應用市場上就會出現了。
後續規劃
鴻蒙OS爲消費者創建便捷的購物超級終端模式提供了可能,隨着鴻蒙生態的豐富,人們的購物形式也會隨之出現新的改變。京東將從用戶角度出發,結合鴻蒙OS,讓更多的用戶在更多的設備和場景享受京東的優質服務,敬請期待……
— 完 —