最近,羊羊乐儿在开发一款HarmonyOS2.0的软件,采用的js+java混合开发模式,js与hml主要用于页面UI设计,java则主要用于提供软件所需要的能力!但是,在实现记录是否已完成软件初次开启,不再推送初次启动页的时候,却遇到了一些小问题,不过最终还是解决了,下面就来给大家分享一下我的经验吧!
事情是这样子的,羊羊乐儿将已在自己鸿蒙设备上测试通过的版本,放到了云端的mate30测试,却发现运行以后,界面一片空白,什么也不加载,于是去鸿蒙官网又仔细查了一下:
原来是API6已经不再维护之前的数据存储接口了,而云端的mate30鸿蒙则正是这个API版本!
于是呢,羊羊乐儿就在自己的启动代码,里引入了新的'@ohos.data.storage'类,并使用新的方式,制作了一份用于判断初次启动页是否完成的验证!
就这样,羊羊乐儿再一次将新生成的hap包,推至了云端API6接口的mate30,看起来好像是成功了,可以显示出页面了!
然而,事情并没有这么简单,当我再将hap包推至自己的鸿蒙设备时,我发现我自己的鸿蒙设备又不能加载出页面了!而且,我将try和catch的内容对调,重新打包推至自己的鸿蒙设备也是如此,并且这样的版本连云端api6的mate30也不能用了 !大概分析了一下原因:
一旦你在page所对应的js里import了'@ohos.data.storage'这个新类,那低于API6的鸿蒙设备就会造成加载不出这个页面,而如果是在API6的环境里import'@system.storage'这个旧类,你不去调用里面的参数的话,那么它不会影响到。可是这样的话,引入新的类旧的没发工作,不引入新的类那新的Api6又不能调用之前的存取代码,那不就无解了么?
在这里,羊羊乐儿也是纳闷了很久,不过还是想到了解决办法:
既然这样的话,那我就不把这个需要调用存取,判断是否完成初次启动的页面,作为第一个page了!我先来检查一下当前设备的API版本,然后再推送不同的数据检测页和相应的pages方案不就好了么,分两个版本做pages,一个版本只import新类,一个只引用旧的类!
好,马上行动,很快羊羊乐儿就在官网找到了ohos.system.version.SystemVersion,这样一个类,它可以检测出当前鸿蒙设备的Api版本号。
不过呢,它这是一个java api,js它是没办法直接用的,但是没有关系,鸿蒙它提供了js调用PA能力的方式:
具体怎么操作,大家可以去鸿蒙开发者官网了解,这里就直接上代码了!
这是java端的代码,这里用的是Internal Ability方式:
package com.agger.harmonyosthemeseditor;
import ohos.ace.ability.AceInternalAbility;
import ohos.app.AbilityContext;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
import ohos.utils.zson.ZSONObject;
import ohos.system.version.SystemVersion;
import java.util.HashMap;
import java.util.Map;
public class AGIModuleInternalAbility extends AceInternalAbility {
//使用代码时,请自行更换为您项目的BundleName与AbilityName
private static final String BUNDLE_NAME = "com.agger.harmonyosthemeseditor";
private static final String ABILITY_NAME = "com.agger.harmonyosthemeseditor.AGIModuleInternalAbility";
private static final int SUCCESS = 0;
private static final int ERROR = 1;
private static final int GetAPIVersion = 101;
private static AGIModuleInternalAbility instance;
private AbilityContext abilityContext;
//用于读取js端传递的data数据,本js调用PA能力,js端无需传递任何数据
/*public class RequestParam_GetAPIVersion {
private int targetApi;
private int minApi;
public int getTargetApi() {
return targetApi;
}
public void setTargetApi(int targetApi) {
this.targetApi = targetApi;
}
public int getMinApi() {
return minApi;
}
public void setMinApi(int minApi) {
this.minApi = minApi;
}
}*/
public AGIModuleInternalAbility()
{
super(BUNDLE_NAME, ABILITY_NAME);
}
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option)
{
switch (code)
{
case GetAPIVersion:
{
/*用于解析js端传递的数据,本js调用PA能力,js端无需传递任何数据
String zsonStr = data.readString();
RequestParam param = ZSONObject.stringToClass(zsonStr, RequestParam.class);
try {param = ZSONObject.stringToClass(dataStr, RequestParam.class);}
catch (RuntimeException e) {}*/
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", SUCCESS);
int API_Version_Code = 0;
try{
SystemVersion _SystemVersion = new SystemVersion();
API_Version_Code = _SystemVersion.getApiVersion();
}catch (Exception ex){}
result.put("abilityResult", API_Version_Code);
if (option.getFlags() == MessageOption.TF_SYNC) {
reply.writeString(ZSONObject.toZSONString(result));
} else {
// ASYNC
MessageParcel responseData = MessageParcel.obtain();
responseData.writeString(ZSONObject.toZSONString(result));
IRemoteObject remoteReply = reply.readRemoteObject();
try {
remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
} catch (RemoteException exception) {
return false;
} finally {
responseData.reclaim();
}
}
break;
}
default:
{
Map<String, Object> result = new HashMap<String, Object>();
result.put("abilityError", ERROR);
reply.writeString("service not defined");
}
}
return true;
}
/**
* Internal ability 注册接口。
*/
public static void register(AbilityContext abilityContext) {
instance = new AGIModuleInternalAbility();
instance.onRegister(abilityContext);
}
private void onRegister(AbilityContext abilityContext) {
this.abilityContext = abilityContext;
this.setInternalAbilityHandler((code, data, reply, option) -> {
return this.onRemoteRequest(code, data, reply, option);
});
}
/**
* Internal ability 注销接口。
*/
public static void unregister() {
instance.onUnregister();
}
private void onUnregister() {
abilityContext = null;
this.setInternalAbilityHandler(null);
}
}
到了这里,别忘了修改您的MainAbility,分别在onStart和onStop里面增添register和unregister!
@Override
public void onStart(Intent intent)
{
AGIModuleInternalAbility.register(this);
super.onStart(intent);
this.getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
if (verifySelfPermission("ohos.permission.DISTRIBUTED_DATA") != IBundleManager.PERMISSION_GRANTED || verifySelfPermission("ohos.permission.DISTRIBUTED_DATASYNC") != IBundleManager.PERMISSION_GRANTED) {
// 应用未被授予权限
requestPermissionsFromUser(new String[] { "ohos.permission.DISTRIBUTED_DATA","ohos.permission.DISTRIBUTED_DATASYNC"} ,1);
} else {
// 权限已被授予
}
}
@Override
public void onStop() {
AGIModuleInternalAbility.unregister();
super.onStop();
}
这是js端的代码,如果您采用的不是Internal Ability方式,须自行修改action.abilityType
import router from '@system.router';
import prompt from '@system.prompt';
// abilityType: 0-Ability; 1-Internal Ability
const ABILITY_TYPE_EXTERNAL = 0;
const ABILITY_TYPE_INTERNAL = 1;
// syncOption(Optional, default sync): 0-Sync; 1-Async
const ACTION_SYNC = 0;
const ACTION_ASYNC = 1;
const ACTION_MESSAGE_CODE_GetAPIVersion = 101;
export default {
onShow : async function()
{
var actionData = {};
actionData.targetApi = 6;
actionData.minApi = 4;
var action = {};
//使用代码时,请自行更换为您项目的BundleName与AbilityName
action.bundleName = 'com.agger.harmonyosthemeseditor';
action.abilityName = 'com.agger.harmonyosthemeseditor.AGIModuleInternalAbility';
action.messageCode = ACTION_MESSAGE_CODE_GetAPIVersion;
action.data = actionData;
action.abilityType = ABILITY_TYPE_INTERNAL;
action.syncOption = ACTION_SYNC;
var result = await FeatureAbility.callAbility(action);
var ret = JSON.parse(result);
/*可以写个toast试验一下,是不是真的可以检查版本
prompt.showToast
(
{
message: '当前鸿蒙API版本是:' + JSON.stringify(ret.abilityResult)
}
);*/
if(ret.abilityResult >= 6)
{
router.push ({uri:'pages/index/api_6/index'});
}else
{
router.push ({uri:'pages/index/api_lower6/index'});
}
},
}
好啦,这样就能根据不同API版本的设备,推送不同的pages了!经多次试验,应用当前解决方案,大部分项目都可以在平板/手机/智慧屏上完美工作,感谢大家的阅读~