京東APP鴻蒙版上架實(shí)踐
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
背景
隨著鴻蒙2.0的發(fā)布,華為部分手機(jī)用戶迎來(lái)鴻蒙時(shí)代,京東作為華為鴻蒙OS的合作APP,首次投入鴻蒙應(yīng)用商用版開(kāi)發(fā),目前已上架V10.0.2版本。
鴻蒙OS特性
2021年6月3日,華為舉行了鴻蒙OS2.0發(fā)布會(huì)。鴻蒙OS帶來(lái)了全新桌面及用戶體驗(yàn),如桌面圖標(biāo)支持上滑呼出快捷卡片,原子化能力能通過(guò)鴻蒙設(shè)備間流轉(zhuǎn)實(shí)現(xiàn)快速分享、顯示,以及統(tǒng)一控制中心(手勢(shì):右上角下滑)、服務(wù)中心(手勢(shì):屏幕左下角或右下角向側(cè)上方滑動(dòng))等。
Android工程鴻蒙化
01 背景
為了利用上鴻蒙的特性,我們開(kāi)發(fā)者需要盡快的將App鴻蒙化。但是將整個(gè)App鴻蒙化的工作量是特別龐大的,那么有沒(méi)有一種方式既能利用鴻蒙的特性也能快速適配呢,答案是有的,那就是混合包開(kāi)發(fā)模式,整個(gè)App基本上沒(méi)有大的修改,只需要新增鴻蒙相關(guān)模塊用來(lái)實(shí)現(xiàn)鴻蒙相關(guān)特性即可。京東App鴻蒙版能夠做到快速適配上線,并擁有鴻蒙特性,就是利用了這種開(kāi)發(fā)模式。下面我們將以京東App鴻蒙版為例,具體介紹下相關(guān)流程。
02 Android工程改造
1.我們需要依賴?guó)櫭傻囊粋€(gè)兼容包(包文件可以聯(lián)系我們?nèi)〉?,將我們現(xiàn)有的Application繼承自HarmonyApplication,僅需編譯依賴,不需要真正打進(jìn)App中。
- compileOnly files('libs/abilityshell_ide_java.jar')
2.在AndroidManifest.xml中,向根節(jié)點(diǎn)下增加。
- <uses-feature android:name="zidane.software.ability" android:required="false" />
3.向application節(jié)點(diǎn)下新增子節(jié)點(diǎn)。
- <meta-data android:name="permZA" android:value="true" />
- <meta-data android:name="multiFrameworkBundle" android:value="true" />
自此已經(jīng)可以構(gòu)建出鴻蒙需要的apk包了,大家也可以通過(guò)配置編譯變體等形式,構(gòu)建鴻蒙版本的apk包。
注意:鴻蒙包中混入的apk必須要是64位的。
03 配置鴻蒙工程
1.在鴻蒙工程中entry module中的build.gradle里,增加混入apk文件配置。
- legacyApkOptions{
- legacyApk rootProject.file('android_entry.apk').absolutePath //混入apk的存放路徑
- signConfig{
- storeFile rootProject.file('xxx.keystore') //混入apk所用簽名文件
- }
- }
整體配置如下圖 :
簽名改造,我們需要根據(jù)Android apk的簽名來(lái)做鴻蒙應(yīng)用簽名的申請(qǐng),需要將.keystore或.jks格式的簽名文件轉(zhuǎn)換成.p12文件,簽名秘鑰和別名保持不變。具體轉(zhuǎn)換步驟,大家可以自行搜索。
參考: 在轉(zhuǎn)換.p12文件時(shí),我們遇到了問(wèn)題,由于我們Android的簽名格式是.keystore,轉(zhuǎn)出來(lái)的.p12文件有問(wèn)題無(wú)法申請(qǐng)鴻蒙應(yīng)用證書,經(jīng)過(guò)和華為方面溝通,我們將鴻蒙應(yīng)用的簽名秘鑰和別名保持和Android的一致,解決了打包問(wèn)題。
配置文件增加屬性,在鴻蒙工程的每個(gè)feature module的config.json app節(jié)點(diǎn)下,增加originalName,表示混入的apk包名,同時(shí)要將bundleName的值也改成一致。
在entry模塊下,新建一個(gè)空的Ability類并配置在config.json里作為啟動(dòng)入口,如:
- "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"
- ],
自此已經(jīng)可以構(gòu)建出包含原有Android功能的鴻蒙包了。
Android鴻蒙互調(diào)用
01 從Android啟動(dòng)鴻蒙組件
我們需要集成鴻蒙的一個(gè)jar包(可以聯(lián)系我們獲得此文件),來(lái)實(shí)現(xiàn)從Android啟動(dòng)鴻蒙的組件。如:
- 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 鴻蒙模塊調(diào)用Android
鴻蒙啟動(dòng)Android組件
鴻蒙里本身是支持啟動(dòng)Android組件的,只需要在Intent里增加一個(gè)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);
鴻蒙模塊調(diào)用Android現(xiàn)有能力
在Android包里,已經(jīng)有了很多現(xiàn)有功能,如埋點(diǎn)收集、用戶登錄態(tài)獲取、定位、地址等等,在鴻蒙模塊里需要用到這些功能時(shí),我們?yōu)榱斯?jié)省時(shí)間暫時(shí)沒(méi)有再去開(kāi)發(fā)一遍鴻蒙版,我們利用了Java的反射技術(shù)來(lái)搞定。經(jīng)過(guò)驗(yàn)證,在Android中反射鴻蒙以及鴻蒙中反射Android都是可以的。
03 獲取當(dāng)前是否為鴻蒙系統(tǒng)
在有些場(chǎng)景下,我們需要知道當(dāng)前系統(tǒng)的運(yùn)行環(huán)境是不是鴻蒙系統(tǒng),可以使用以下代碼段來(lái)實(shí)現(xiàn)。
- 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特性+購(gòu)物應(yīng)用場(chǎng)景開(kāi)發(fā)
鴻蒙OS打破了設(shè)備間的壁壘,對(duì)用戶及應(yīng)用開(kāi)發(fā)者來(lái)說(shuō),形成了超級(jí)終端。超級(jí)終端包含手機(jī)、大屏、平板,未來(lái)或許會(huì)有更多的設(shè)備加入,設(shè)備間協(xié)同合作讓購(gòu)物體驗(yàn)變得優(yōu)質(zhì)。每個(gè)設(shè)備不再是孤立的個(gè)體,而是基于鴻蒙操作系統(tǒng)的智慧終端,即便用戶拿著不同的設(shè)備,也可以有很好的體驗(yàn)。通過(guò)一鍵流轉(zhuǎn)實(shí)現(xiàn)跨設(shè)備間的數(shù)據(jù)傳輸,從而實(shí)現(xiàn)無(wú)縫的購(gòu)物體驗(yàn)。
01 流轉(zhuǎn):直播間FA
介紹
流轉(zhuǎn)泛指多設(shè)備間的分布式操作,打破設(shè)備界限,多設(shè)備聯(lián)動(dòng),使用戶應(yīng)用程序可分可合、可流轉(zhuǎn)。流轉(zhuǎn)按照體驗(yàn)可分為跨端遷移和多端協(xié)同。流轉(zhuǎn)支持免安裝運(yùn)行FA。京東App鴻蒙版本中的直播FA就利用了流轉(zhuǎn)能力,將當(dāng)前手機(jī)的直播流轉(zhuǎn)至TV端,做到無(wú)縫銜接,并支持通過(guò)手機(jī)端控制TV端直播顯示的功能。效果如下:
開(kāi)發(fā)
我們以京東App鴻蒙版中直播FA的流轉(zhuǎn)開(kāi)發(fā)經(jīng)驗(yàn)進(jìn)行介紹,如何具備流轉(zhuǎn)能力。
1.權(quán)限要求
由于使用到了分布式能力,我們需要先把權(quán)限配置好,在對(duì)應(yīng)的module的config.json下,增加以下權(quán)限:
- ohos.permission.GET_DISTRIBUTED_DEVICE_INFO
- ohos.permission.DISTRIBUTED_DATASYNC
- ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE
同時(shí)在Ability里,需要增加動(dòng)態(tài)權(quán)限申請(qǐng)。
- requestPermissionsFromUser(
- new String[]{SystemPermission.DISTRIBUTED_DATASYNC},
- Constants.PermissionCode.PERMISSION_DISTRIBUTED_DATASYNC);
2.關(guān)鍵接口

3.功能實(shí)現(xiàn)
a. 通過(guò)流轉(zhuǎn)服務(wù)注冊(cè)管理器,將當(dāng)前FA注冊(cè),注冊(cè)時(shí)可以指定流轉(zhuǎn)的過(guò)濾條件,如設(shè)備類型、目標(biāo)設(shè)備等等:
b. 當(dāng)需要流轉(zhuǎn)時(shí),我們通過(guò)流轉(zhuǎn)服務(wù)注冊(cè)管理器獲取當(dāng)前滿足條件的設(shè)備列表:
系統(tǒng)會(huì)自動(dòng)查找設(shè)備,將滿足條件的設(shè)備自動(dòng)展示出來(lái)供用戶選擇,當(dāng)用戶點(diǎn)擊某個(gè)設(shè)備后,就會(huì)回調(diào)IContinuationDeviceCallback的onDeviceConnectDone方法,獲取到目標(biāo)設(shè)備的Id后,就可以啟動(dòng)目標(biāo)設(shè)備的FA。
c. 啟動(dòng)遠(yuǎn)程FA
需要注意的是,在啟動(dòng)對(duì)端設(shè)備上FA時(shí),我們要確保對(duì)端設(shè)備的分布式能力已經(jīng)被初始化。
02 FA近場(chǎng)分享:商詳FA
介紹
FA近場(chǎng)分享能力依賴于華為分享服務(wù),可以快速實(shí)現(xiàn)FA分享的功能。較單純的使用分布式FA流轉(zhuǎn)功能,為開(kāi)發(fā)者免除了設(shè)備發(fā)現(xiàn)功能,并且沒(méi)有了同賬號(hào)同網(wǎng)絡(luò)等限制條件。在京東App鴻蒙版中,商詳FA就使用了此功能實(shí)現(xiàn)了FA的近場(chǎng)分享,并且能夠做到免安裝打開(kāi)商詳頁(yè)面。下圖分別是A向B發(fā)送商詳FA 和 B接收商詳FA。


開(kāi)發(fā)
我們將以在京東App鴻蒙版中的相關(guān)開(kāi)發(fā)經(jīng)驗(yàn)介紹下如何進(jìn)行FA近場(chǎng)分享的開(kāi)發(fā)。
工作原理圖示:

由于功能依賴華為分享服務(wù),我們首先要引入IDL文件。
導(dǎo)入IDL文件
在商詳FA module中java同級(jí)目錄,創(chuàng)建idl目錄,并創(chuàng)建包名com.huawei.hwshare.third,在此包名下創(chuàng)建IHwShareCallback.idl和 IHwShareService.idl文件,文件具體內(nèi)容如下:
- 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);
- }

對(duì)分享能力進(jìn)行封裝
以下是我們?cè)谏淘擣A中封裝好的代碼,大家可以直接使用。
- 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的圖標(biāo) byte[] len < 32768 非必須,不傳默認(rèn)取應(yīng)用圖標(biāo)
- public static final String HM_FA_ICON = "ohos_fa_icon";
- // FA的名字 String len < 1024 非必須,不傳默認(rèn)取應(yīng)用名
- 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 暫時(shí)只有0 非必須,默認(rèn)為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());
- //服務(wù)綁定回調(diào)
- 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 {
- //華為分享認(rèn)證授權(quán)
- 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;
- }
- };
- //華為分享認(rèn)證授權(quán)回調(diào)
- 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的實(shí)例對(duì)象
- *
- \* @param context 程序Context
- \* @return ShareFaManager實(shí)例對(duì)象
- */
- 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.");
- }
- }
- // 不使用時(shí)斷開(kāi)
- mHandler.postTask(mTask, UNBIND_TIME);
- }
- /**
- \* 開(kāi)始分享
- *
- \* @param appId 開(kāi)發(fā)者聯(lián)盟網(wǎng)站創(chuàng)建鴻蒙服務(wù)/鴻蒙應(yīng)用時(shí)生成的appid
- \* @param pacMap 服務(wù)信息載體
- */
- public void shareFaInfo(String appId, PacMapEx pacMap) {
- if (mContext == null) {
- return;
- }
- mAppId = appId;
- mSharePacMap = pacMap;
- mHandler.removeTask(mTask);
- shareFaInfo();
- bindShareService();
- }
- /**
- \* 綁定華為分享服務(wù)
- */
- 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.開(kāi)始分享
我們將參數(shù)進(jìn)行組裝,調(diào)用ShareFaManager的shareFaInfo方法即可自動(dòng)的完成FA分享功能。如我們將商詳FA進(jìn)行分享:

注意
- 使用時(shí)要主要傳遞的數(shù)據(jù)不要超過(guò)限定的大小,否則會(huì)分享失敗并導(dǎo)致程序崩潰。
- 在對(duì)端接收到分享后,我們需要將自定義的參數(shù)取出來(lái),從Intent中取sharing_fa_extra_info即可。
Ps:針對(duì)遠(yuǎn)距離的場(chǎng)景,華為也給出了解決方案,通過(guò)暢連即可分享購(gòu)物鏈接。值得注意的是,此時(shí)好友還可以通過(guò)屏幕共享在商品頁(yè)面進(jìn)行涂鴉互動(dòng)。
03 服務(wù)卡片:搜索卡片
用戶上滑 App 圖標(biāo)即可生成萬(wàn)能卡片 ,在桌面呈現(xiàn)更豐富的信息,卡片信息支持實(shí)時(shí)更新,減少了 App 加載的時(shí)間,如目前京東app,用戶上滑 App 圖標(biāo)可打開(kāi)快捷搜索入口。
介紹
FA卡片是FeatureAbility的Page模板的一種界面展示形式。FA卡片常用于嵌入到其他應(yīng)用中作為其界面的一部分顯示,并支持基礎(chǔ)的交互功能??ㄆ褂梅阶鳛榭ㄆ故镜乃拗髫?fù)責(zé)顯示卡片,卡片使用方的典型應(yīng)用就是桌面應(yīng)用。卡片使用方僅限系統(tǒng)應(yīng)用。
當(dāng)FA規(guī)格小于10M時(shí),可以支持免安裝運(yùn)行。系統(tǒng)最大支持500個(gè)卡片,相同名稱的卡片實(shí)例最大是32個(gè)。
通過(guò)服務(wù)卡片的一些特點(diǎn),如定時(shí)更新、免安裝運(yùn)行等,可以很好的進(jìn)行快捷入口的引導(dǎo)。如我們可以在卡片上展示活動(dòng)商品,并定期更新,用戶可以免安裝的打開(kāi)活動(dòng)詳情,當(dāng)用戶產(chǎn)生進(jìn)一步購(gòu)買欲望時(shí),用戶可下載整個(gè)App進(jìn)行下單。
開(kāi)發(fā)
卡片的開(kāi)發(fā)支持JS和Java兩種方式。在京東App鴻蒙版中的搜索FA里,我們加入了FA卡片,可以直達(dá)搜索。下面我們將以此為例進(jìn)行開(kāi)發(fā)步驟的講解。
1.卡片配置
首先要在搜索FA的config.json中配置forms節(jié)點(diǎn),比如:

我們給SearchAbility節(jié)點(diǎn)下添加forms節(jié)點(diǎn),就表示這個(gè)卡片的創(chuàng)建及管理由SearchAbility來(lái)負(fù)責(zé)。
注意:必須要設(shè)置label屬性,必須是資源形式的且不能是包名。
屬性解釋:

實(shí)現(xiàn)卡片相關(guān)回調(diào)
在SearchAbility中,復(fù)寫以下幾個(gè)方法:
創(chuàng)建:在創(chuàng)建卡片時(shí),我們可以從Intent中獲取當(dāng)前要?jiǎng)?chuàng)建卡片的Id,如:

這是一個(gè)很簡(jiǎn)單的卡片,我們沒(méi)有對(duì)卡片中的視圖設(shè)置任何數(shù)據(jù)和事件,那么點(diǎn)擊卡片后,打開(kāi)的就是負(fù)責(zé)管理卡片的Ability。如果需要設(shè)置數(shù)據(jù)和事件,可以使用以下方式
創(chuàng)建ComponentProvider;
通過(guò)ComponentProvider設(shè)置對(duì)應(yīng)View的數(shù)據(jù),以及點(diǎn)擊事件,目前能夠支持的事件有START_ABILITY和START_SERVICE兩類;
將ComponentProvider對(duì)象合并入ProviderFormInfo中。

更新:當(dāng)觸發(fā)了更新卡片方法時(shí),我們可以進(jìn)行數(shù)據(jù)更新,并將最新的數(shù)據(jù)更新到卡片View上。

刪除:當(dāng)卡片使用方將卡片刪除,我們可能需要將對(duì)應(yīng)卡片在App內(nèi)的相關(guān)持久化數(shù)據(jù)進(jìn)行刪除。

3.配置EntryCard目錄
配置EntryCard目錄,以便讓系統(tǒng)能夠識(shí)別出服務(wù)卡片,并展示在服務(wù)中心的推薦里。新建應(yīng)用時(shí)可以勾選自動(dòng)生成,如果是之前IDE創(chuàng)建的工程,則需要手動(dòng)補(bǔ)充上。
1)在工程根目錄下創(chuàng)建EntryCard目錄;
2) EntryCard目錄下,創(chuàng)建一個(gè)文件夾,取名為擁有卡片的FA工程名,如我們的搜索FA擁有服務(wù)卡片,搜索FA的工程名叫searchfeature,那我們就創(chuàng)建一個(gè)文件夾,名字就叫做searchfeature;
3)在searchfeature目錄下創(chuàng)建base/snapshot兩級(jí)目錄,在其中放置我們的卡片圖片,其命名方式為formnamedimensions,如搜索卡片的卡片名稱配置的是search_card,尺寸是22的,那么這個(gè)圖片就命名為search_card2x2.png。
鴻蒙App打包及上架
01 打包構(gòu)建
通過(guò)以上配置,我們已經(jīng)可以進(jìn)行鴻蒙App的構(gòu)建了。目前鴻蒙App分為兩種構(gòu)建形式,debug和release,可以通過(guò)DevEco工具自帶的編譯任務(wù)或者使用gradle的assembleDebug signReleaseApp任務(wù)進(jìn)行構(gòu)建。

其中debug模式構(gòu)建方式出來(lái)的產(chǎn)物是多個(gè)目標(biāo)設(shè)備的多個(gè).hap文件,每個(gè)FA都會(huì)構(gòu)建出各自的.hap文件;release會(huì)構(gòu)建出一個(gè).app文件,我們需要將此文件進(jìn)行上架發(fā)布。

安裝及運(yùn)行
開(kāi)發(fā)者無(wú)法安裝.app安裝包,此文件只能用于上架應(yīng)用市場(chǎng)。
通過(guò)adb shell bm get udid獲取設(shè)備UDID后,錄入到開(kāi)發(fā)者中心,并生成證書文件,我們就可以安裝.hap包。
安裝時(shí)可以將文件push到手機(jī)某個(gè)目錄下(如sdcard/hmphone),然后使用adb shell bm install p /sdcard/hmphone/進(jìn)行安裝,每次安裝可以先刪除之前文件。
注意: 由于我們無(wú)法安裝驗(yàn)證.app包,我們要保證在debug和release兩種構(gòu)建模式下,我們的代碼不會(huì)發(fā)生改變。
02 應(yīng)用上架及發(fā)布
1.如果還沒(méi)有在開(kāi)發(fā)者中心創(chuàng)建鴻蒙應(yīng)用的話,需要先新增一個(gè)鴻蒙應(yīng)用,包名和之前Android的包名保持一致,并關(guān)聯(lián)到同一個(gè)項(xiàng)目中。

選擇我們創(chuàng)建的鴻蒙應(yīng)用,在【應(yīng)用信息】頁(yè)面中,將應(yīng)用安裝與升級(jí)修改為如下圖所示。

在【版本信息】頁(yè)面中,點(diǎn)擊【版本/升級(jí)】創(chuàng)建新版本,在新版本頁(yè)面中的【軟件版本】模塊下,上傳我們構(gòu)建的.app軟件包后并勾選,在當(dāng)前頁(yè)面填入相關(guān)信息后即可提交審核,待審核通過(guò)后,在應(yīng)用市場(chǎng)上就會(huì)出現(xiàn)了。

后續(xù)規(guī)劃
鴻蒙OS為消費(fèi)者建立便捷的購(gòu)物超級(jí)終端模式提供了可能,隨著鴻蒙生態(tài)的豐富,人們的購(gòu)物形式也會(huì)隨之出現(xiàn)新的改變。京東將從用戶角度出發(fā),結(jié)合鴻蒙OS,讓更多的用戶在更多的設(shè)備和場(chǎng)景享受京東的優(yōu)質(zhì)服務(wù),敬請(qǐng)期待……
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)