隨著鴻蒙 2.0 的發布,華為部分手機用戶迎來鴻蒙時代,京東作為華為鴻蒙 OS 的合作 APP,首次投入鴻蒙應用商用版開發,目前已上架 V10.0.2 版本。
鴻蒙 OS 特性
2021 年 6 月 2 日,華為舉行了鴻蒙 OS 2.0 發布會。鴻蒙 OS 帶來了全新桌面及用戶體驗。
如桌面圖標支持上滑呼出快捷卡片,原子化能力能通過鴻蒙設備間流轉實現快速分享、顯示,以及統一控制中心(手勢:右上角下滑)、服務中心(手勢:屏幕左下角或右下角向側上方滑動)等。
Android 工程鴻蒙化
為了利用上鴻蒙的特性,我們開發者需要盡快的將 App 鴻蒙化。
但是將整個 App 鴻蒙化的工作量是特別龐大的,那么有沒有一種方式既能利用鴻蒙的特性也能快速適配呢?
答案是有的,那就是混合包開發模式,整個 App 基本上沒有大的修改,只需要新增鴻蒙相關模塊用來實現鴻蒙相關特性即可。
京東 App-鴻蒙版能夠做到快速適配上線,并擁有鴻蒙特性,就是利用了這種開發模式。下面我們將以京東 App-鴻蒙版為例,具體介紹下相關流程。
Android 工程改造
①我們需要依賴鴻蒙的一個兼容包(包文件可以聯系我們取得),將我們現有的 Application 繼承自 HarmonyApplication,僅需編譯依賴,不需要真正打進 App 中。
compileOnly files(‘libs/abilityshell_ide_java.jar’)
②在 AndroidManifest.xml 中,向根節點下增加。
《uses-feature android:name=“zidane.software.ability” android:required=“false” /》
③向 application 節點下新增子節點。
《meta-data android:name=“permZA” android:value=“true” /》
《meta-data android:name=“multiFrameworkBundle” android:value=“true” /》
自此已經可以構建出鴻蒙需要的 apk 包了,大家也可以通過配置編譯變體等形式,構建鴻蒙版本的 apk 包。
注意:鴻蒙包中混入的 apk 必須要是 64 位的。
配置鴻蒙工程
①在鴻蒙工程中 entry module 中的 build.gradle 里,增加混入 apk 文件配置。
legacyApk rootProject.file(‘android_entry.apk’).absolutePath //混入apk的存放路徑
signConfig{
storeFile rootProject.file(‘xxx.keystore’) //混入apk所用簽名文件
}
}
整體配置如下圖 :
②簽名改造,我們需要根據 Android apk 的簽名來做鴻蒙應用簽名的申請,需要將 .keystore 或 .jks 格式的簽名文件轉換成 .p12 文件,簽名秘鑰和別名保持不變。具體轉換步驟,大家可以自行搜索。
參考:在轉換 .p12 文件時,我們遇到了問題,由于我們 Android 的簽名格式是 .keystore,轉出來的 .p12 文件有問題無法申請鴻蒙應用證書。
經過和華為方面溝通,我們將鴻蒙應用的簽名秘鑰和別名保持和Android的一致,解決了打包問題。
③配置文件增加屬性,在鴻蒙工程的每個 feature module 的 config.json app 節點下,增加 originalName,表示混入的 apk 包名,同時要將 bundleName 的值也改成一致。
④在 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-鴻蒙互調用
①從 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);
②鴻蒙模塊調用 Android
鴻蒙啟動 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);
鴻蒙模塊調用 Android 現有能力:在 Android 包里,已經有了很多現有功能,如埋點收集、用戶登錄態獲取、定位、地址等等。
在鴻蒙模塊里需要用到這些功能時,我們為了節省時間暫時沒有再去開發一遍鴻蒙版,我們利用了 Java 的反射技術來搞定。
經過驗證,在 Android 中反射鴻蒙以及鴻蒙中反射 Android 都是可以的。
③獲取當前是否為鴻蒙系統
在有些場景下,我們需要知道當前系統的運行環境是不是鴻蒙系統,可以使用以下代碼段來實現。
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 打破了設備間的壁壘,對用戶及應用開發者來說,形成了超級終端。超級終端包含手機、大屏、平板,未來或許會有更多的設備加入,設備間協同合作讓購物體驗變得優質。
每個設備不再是孤立的個體,而是基于鴻蒙操作系統的智慧終端,即便用戶拿著不同的設備,也可以有很好的體驗。
通過一鍵流轉實現跨設備間的數據傳輸,從而實現無縫的購物體驗。
流轉:直播間 FA
介紹:流轉泛指多設備間的分布式操作,打破設備界限,多設備聯動,使用戶應用程序可分可合、可流轉。流轉按照體驗可分為跨端遷移和多端協同。流轉支持免安裝運行 FA。
京東 App-鴻蒙版本中的直播 FA 就利用了流轉能力,將當前手機的直播流轉至 TV 端,做到無縫銜接,并支持通過手機端控制 TV 端直播顯示的功能。
開發:我們以京東 App-鴻蒙版中直播 FA 的流轉開發經驗進行介紹,如何具備流轉能力。
權限要求:由于使用到了分布式能力,我們需要先把權限配置好,在對應的 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);
關鍵接口如下圖:
功能實現如下:
a.通過流轉服務注冊管理器,將當前 FA 注冊,注冊時可以指定流轉的過濾條件,如設備類型、目標設備等等:
b.當需要流轉時,我們通過流轉服務注冊管理器獲取當前滿足條件的設備列表:
系統會自動查找設備,將滿足條件的設備自動展示出來供用戶選擇,當用戶點擊某個設備后,就會回調 IContinuationDeviceCallback 的 onDeviceConnectDone 方法,獲取到目標設備的 Id 后,就可以啟動目標設備的 FA。
c.啟動遠程 FA。需要注意的是,在啟動對端設備上 FA 時,我們要確保對端設備的分布式能力已經被初始化。
FA 近場分享:商詳 FA
介紹:FA 近場分享能力依賴于華為分享服務,可以快速實現 FA 分享的功能。
較單純的使用分布式 FA 流轉功能,為開發者免除了設備發現功能,并且沒有了同賬號同網絡等限制條件。
在京東 App-鴻蒙版中,商詳 FA 就使用了此功能實現了 FA 的近場分享,并且能夠做到免安裝打開商詳頁面。
下圖分別是 A 向 B 發送商詳 FA 和 B 接收商詳 FA。開發:我們將以在京東 App-鴻蒙版中的相關開發經驗介紹下如何進行 FA 近場分享的開發。
工作原理圖示:
由于功能依賴華為分享服務,我們首先要引入 IDL 文件。
①導入 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);
}
②對分享能力進行封裝
以下是我們在商詳 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);
}
}
③開始分享
我們將參數進行組裝,調用 ShareFaManager 的 shareFaInfo 方法即可自動的完成 FA 分享功能。
如我們將商詳 FA 進行分享:
注意:
使用時要主要傳遞的數據不要超過限定的大小,否則會分享失敗并導致程序崩潰。
在對端接收到分享后,我們需要將自定義的參數取出來,從 Intent 中取 sharing_fa_extra_info 即可。
Ps:針對遠距離的場景,華為也給出了解決方案,通過暢連即可分享購物鏈接。值得注意的是,此時好友還可以通過屏幕共享在商品頁面進行涂鴉互動。
服務卡片:搜索卡片
用戶上滑 App 圖標即可生成萬能卡片 ,在桌面呈現更豐富的信息,卡片信息支持實時更新,減少了 App 加載的時間,如目前京東 app,用戶上滑 App 圖標可打開快捷搜索入口。
介紹:FA 卡片是 FeatureAbility 的 Page 模板的一種界面展示形式。FA 卡片常用于嵌入到其他應用中作為其界面的一部分顯示,并支持基礎的交互功能。
卡片使用方作為卡片展示的宿主負責顯示卡片,卡片使用方的典型應用就是桌面應用??ㄆ褂梅絻H限系統應用。
當 FA 規格小于 10M 時,可以支持免安裝運行。系統最大支持 500 個卡片,相同名稱的卡片實例最大是 32 個。
通過服務卡片的一些特點,如定時更新、免安裝運行等,可以很好的進行快捷入口的引導。
如我們可以在卡片上展示活動商品,并定期更新,用戶可以免安裝的打開活動詳情,當用戶產生進一步購買欲望時,用戶可下載整個 App 進行下單。
開發:卡片的開發支持 JS 和 Java 兩種方式。在京東 App-鴻蒙版中的搜索 FA 里,我們加入了 FA 卡片,可以直達搜索。下面我們將以此為例進行開發步驟的講解。
①卡片配置
首先要在搜索 FA 的 config.json 中配置 forms 節點,比如:
我們給 SearchAbility 節點下添加 forms 節點,就表示這個卡片的創建及管理由 SearchAbility 來負責。
注意:必須要設置 label 屬性,必須是資源形式的且不能是包名。
屬性解釋:
②實現卡片相關回調
在 SearchAbility 中,復寫以下幾個方法:
創建:在創建卡片時,我們可以從 Intent 中獲取當前要創建卡片的 Id,如:
這是一個很簡單的卡片,我們沒有對卡片中的視圖設置任何數據和事件,那么點擊卡片后,打開的就是負責管理卡片的 Ability。
如果需要設置數據和事件,可以使用以下方式:
創建 ComponentProvider。
通過 ComponentProvider 設置對應 View 的數據,以及點擊事件,目前能夠支持的事件有 START_ABILITY 和 START_SERVICE 兩類。
將 ComponentProvider 對象合并入 ProviderFormInfo 中。
更新:當觸發了更新卡片方法時,我們可以進行數據更新,并將最新的數據更新到卡片 View 上。
刪除:當卡片使用方將卡片刪除,我們可能需要將對應卡片在 App 內的相關持久化數據進行刪除。
③配置 EntryCard 目錄
配置 EntryCard 目錄,以便讓系統能夠識別出服務卡片,并展示在服務中心的推薦里。
新建應用時可以勾選自動生成,如果是之前 IDE 創建的工程,則需要手動補充上:
在工程根目錄下創建 EntryCard 目錄。
EntryCard 目錄下,創建一個文件夾,取名為擁有卡片的 FA 工程名,如我們的搜索 FA 擁有服務卡片,搜索 FA 的工程名叫 searchfeature,那我們就創建一個文件夾,名字就叫做 searchfeature。
在 searchfeature 目錄下創建 base/snapshot 兩級目錄,在其中放置我們的卡片圖片,其命名方式為 formname-dimensions。
如搜索卡片的卡片名稱配置的是 search_card,尺寸是 2*2 的,那么這個圖片就命名為 search_card-2x2.png。
鴻蒙 App 打包及上架
打包構建
通過以上配置,我們已經可以進行鴻蒙 App 的構建了。
目前鴻蒙 App 分為兩種構建形式,debug 和 release,可以通過 DevEco 工具自帶的編譯任務或者使用 gradle 的 assembleDebug signReleaseApp 任務進行構建。
其中 debug 模式構建方式出來的產物是多個目標設備的多個 .hap 文件,每個 FA 都會構建出各自的 .hap 文件;release 會構建出一個 .app 文件,我們需要將此文件進行上架發布。
安裝及運行:
①開發者無法安裝 .app 安裝包,此文件只能用于上架應用市場。
②通過 adb shell bm get -udid 獲取設備 UDID 后,錄入到開發者中心,并生成證書文件,我們就可以安裝 .hap 包。
③安裝時可以將文件 push 到手機某個目錄下(如 sdcard/hmphone),然后使用 adb shell bm install -p /sdcard/hmphone/ 進行安裝,每次安裝可以先刪除之前文件。
注意:由于我們無法安裝驗證 .app 包,我們要保證在 debug 和 release 兩種構建模式下,我們的代碼不會發生改變。
應用上架及發布
①如果還沒有在開發者中心創建鴻蒙應用的話,需要先新增一個鴻蒙應用,包名和之前 Android 的包名保持一致,并關聯到同一個項目中。②選擇我們創建的鴻蒙應用,在【應用信息】頁面中,將應用安裝與升級修改為如下圖所示。③在【版本信息】頁面中,點擊【版本/升級】創建新版本,在新版本頁面中的【軟件版本】模塊下,上傳我們構建的 .app 軟件包后并勾選,在當前頁面填入相關信息后即可提交審核,待審核通過后,在應用市場上就會出現了。
后續規劃
鴻蒙 OS 為消費者建立便捷的購物超級終端模式提供了可能,隨著鴻蒙生態的豐富,人們的購物形式也會隨之出現新的改變。
京東將從用戶角度出發,結合鴻蒙 OS,讓更多的用戶在更多的設備和場景享受京東的優質服務,敬請期待……
責任編輯:haq
-
華為
+關注
關注
216文章
34429瀏覽量
251641 -
操作系統
+關注
關注
37文章
6818瀏覽量
123318 -
鴻蒙系統
+關注
關注
183文章
2634瀏覽量
66320 -
HarmonyOS
+關注
關注
79文章
1974瀏覽量
30165
發布評論請先 登錄
相關推薦
評論