一、开发前准备
开发环境
鸿蒙开发使用DevEco Studio开发。具体步骤鸿蒙和Android 开发环境搭建类似。下载HarmonyOS SDK,以及开发工具。
环境准备流程如下:
开发环境搭建步骤详细参照官网下载Studio以及配置SDK,此处不做赘述
官网链接: developer.harmonyos.com/cn/docs/doc…
开发者账号: 为了确保HarmonyOS应用的完整性,HarmonyOS通过数字证书和Profile文件来对应用进行管控,只有签名过的HAP才允许安装到设备上运行。因此,为了保证应用能够安装到调试设备上,您需要提前申请相应的调试证书与调试Profile。
鸿蒙应用开发,如果使用真机调试,必须有开发者账号,绑定应用包名以及签名才能进行开发调试。
华为的开发者平台网站: developer.huawei.com/consumer/cn…
华为智慧服务开发平台: developer.huawei.com/consumer/cn…
使用自己的账号调试demo的话,需要注册自己的华为开发者账号,创建应用以及签名。
- 注册账号,实名认证。
- 创建项目
- 创建应用
- 创建本地签名校验文件
- 账号新增签名文件,账号新增设备
- 给应用创建profile文件并且绑定真机设备
- 下载profile文件,给应用增加签名配置
创建项目:
创建应用:
创建应用包名必须和本地包名实际应用包名一致,否则签名校验不过,没法真机调试
创建本地签名证书文件:
DevEco Studio -> Build -> Generate Key and CSR :
创建证书:
华为智慧服务平台->通用设置->证书管理->新增证书->上传CSR文件
账号下新增设备:
首先获取获取手机udid
adb shell bm get -u
然后在账号下新增设备,填写获取到的UUID号。 手机UDID必须添加到账号下,才能绑定应用测试签名
新增应用Profile:
- 一个证书可以创建100个profile。
- 此处选择必须已经添加到账号下的设备,以及数字证书才能对此包名的应用进行真机调试
华为智慧服务平台->我的项目->项目设置->HAP Provision Profile->添加
选择对应的证书和设备创建profile文件
二、工程创建与调试运行
前面开发环境和开发证书均已准备完整,接下来进行创建工程和调试。
开发工具:
- DevEco Studio: developer.harmonyos.com/cn/develop/…
基本是和Android Studio 一样
创建应用:
选择对应应用类型,是鸿蒙应用还是服务卡片:
目录结构:
基本和Android Studio目录结构一样。
entry:
等价于Android Studio 里的 app。
config.json:
等价于AndroidManifest.xml
具体属性参照:
资源文件分类:
developer.harmonyos.com/cn/docs/doc…
resources
|---base // 默认存在的目录
| |---element // 元素资源目录,存放string,color,dimens等
| | |---string.json
| |---layout // 布局资源目录
| | |---ability_main.xml
| |---graphic // drawable资源目录,存放xml图片如shape,state-container
| | |---bg_white_btn_radius_8.xml
| |---media // 图片目录
| | |---icon.png
|---en_GB-vertical-car-mdpi // 限定词目录示例,需要开发者自行创建
| |---element
| | |---string.json
| |---media
| | |---icon.png
|---rawfile // 默认存在的目录
EntryCard:
新建工程选择了Show In Service Center基本都会自动生成这个目录,这个目录下主要是存放卡片快照。用于在服务中心展示未下载的卡片。一般用默认卡片的视觉图。命名必须是"卡片名称-2x2.png",因为必须有一个2x2的卡片作为默认卡片。
HarmonyDemo
├── EntryCard
│ └── entry // 这里是存放卡片快照的地方,用于在服务中心展示卡片,一般用默认卡片的视觉图。命名必须是"卡片名称-2x2.png"
├── entry
├── agconnect-services.json //华为开发者网站自动生成的,保存应用配置信息的配置文件
├── build.gradle
├── proguard-rules.pro
├── libs
└── src
├── main
│ ├── config.json // 功能等价于 AndroidManifest.xml
│ ├── java // java 代码
│ ├── js // js 代码
│ │ ├── widget2x2 // js卡片所在目录,必须和config.json中jsComponentName一致。
│ │ ├── common
│ │ ├── i18n
│ │ └── pages
│ └── resources // 资源目录
│ ├── base
│ │ ├── element // 类似于android studio values目录,存放string.json,float.json
│ │ ├── graphic // 存放 Drawable Resource File,xml格式写的一些图
│ │ ├── layout // 布局存放目录
│ │ ├── media // 图片资源文件
│ │ └── profile
│ ├── en
│ │ └── element // 英文文字资源定义
│ ├── rawfile
│ └── zh
│ └── element // 中文文字资源定义
js卡片和config.json 对应关系:
开发与调试:
想要在真机上运行,必须进行签名,使用之前生成的证书和签名文件对应用进行签名配置:
添加签名后,本地entry下build.gradle生成的:
到此,鸿蒙demo应用已经可以在自己的鸿蒙真机设备上运行了。
正式签名配置步骤和debug签名配置步骤一样。只是创建正式发布profile不需要选择设备。
三、鸿蒙相关API和Android对应关系与差异
我们目前还是基于HarmonyOS 2.0开发,从上面的目录结构来看,开发方式总体上来说和Android 开发流程几乎完成一致,仅仅SDK以及各个接口变更了。
完整开发文档: developer.harmonyos.com/cn/docs/doc…
先列一下Harmony SDK 和 Android SDK基本组件的对应关系:
ohos.app.Context->android.content.Context
Context 里面的接口用处基本和Android很相似,请求权限、跳转界面、资源管理,系统接口桥梁都类似。
这里不同点是这里增加了些TaskDispatcher任务分发器,系统默认实现了几种任务分发器。类似线程池。方便执行一些异步任务。
详情可以看 线程开发指导
getGlobalTaskDispatcher:全局并发任务分发器,适用于任务之间没有联系的情况
UITaskDispatcher:绑定到应用主线程的专有任务分发器, 由Ability执行getUITaskDispatcher()创建并返回。由该分发器分发的所有的任务都是在主线程上按顺序执行,它在应用程序结束时被销毁。
2. 页面: Page Ability ---> Activity
setUIContent: 设置界面内容,对应setContentView
3. 服务: Service Ability ---> Service
启动页面或服务: startAbility :对应Android的 startActivity 以及 startService
链接服务: connectAbility:对应Android 的 bindService
在Harmony中服务和界面统称Ability, 通过在config.json中修改type定义其类型来标识是服务还是界面。
"abilities": [
{
"orientation": "portrait",
"name": "com.tencent.gallerycard.MainAbility",
"icon": "$media:ic_launcher_app",
"description": "$string:mainability_description",
"formsEnabled": true,
"visible": true,
"label": "$string:entry_label",
"type": "page", // 表示是页面
},
{
"name": "com.tencent.gallerycard.GalleryServiceAbility",
"description": "$string:galleryserviceability_description",
"type": "service" // 表示是服务
}
],
Page Ability 生命周期
Service Ability生命周期:
4. 子页面:AbilitySlice ---> Fragment
目前看AbilitySlice类似于Fragment可以在一个Ability中切换不同的AbilitySlice来更换显示。但是又不同于Fragment, AbilitySlice 作为 Ability的子页面,是完全占用整个Ability窗口的,Ability的整个页面内容都在AbilitySlice中,Fragment可以仅仅占用一部分。
通过AbilitySlice里提供的present方法在同一Page内进行不同的AbilitySlice间的跳转
// 普通跳转
AbilitySlice#present(new TargetAbility(),intent);
// 需要返回结果
AbilitySlice#presentForResult(new TargetAbility(),intent,requestCode);
5. 意图Intent:
名字和Android 上都一样的,用法有些许不同,可以通过设置 FLAG_NOT_OHOS_COMPONENT 来达到跳转android应用的界面
使用如下:
private void goAndroidApp() {
Intent androidIntent = new Intent();
ElementName androidElementName = new ElementName("", "com.tencent.xxx",
"com.tencent.xxx.xxxActivity");
String category = "android.intent.category.DEFAULT";
Set<String> entities = new HashSet<>();
entities.add(category);
androidIntent.setElement(androidElementName);
Operation operation = new OperationBuilder()
.withDeviceId("")
.withBundleName("com.tencent.xxx") // packageName
.withAbilityName("com.tencent.xxx.xxxActivity") // 类似className
.withEntities(entities) // 类似 addCategory
.withAction("android.intent.action.EDIT")
.withUri(Uri.parse(imageUri)) // uri数据,类似Android Intent.setData
.build();
androidIntent.setOperation(operation);
androidIntent.addFlags(Intent.FLAG_NOT_OHOS_COMPONENT); // 跳转非鸿蒙应用
androidIntent.setParam("key", value); // 类似Android Intent putExtras
startAbility(androidIntent);
6. Data Ability ---> Android 上ContentProvider
DataAbilityHelper: query()方法可以根据uri查询文件的ID,操作系统媒体库基本用这个方法
ValuesBucket: 对应android上的 ContentValues
DatabaseHelper:数据库操作类
7. ohos.agp.components.Component ---> Android 上View
- 测量:
onEstimateSize--> Android 上onMeasure - 绘制:
onDraw--> Android 上onDraw
8. ohos.agp.components.ComponentContainer ---> Android 上ViewGroup
- 布局: onArrange---> Android 上 onLayout
这些和Android上不同的点是:鸿蒙中这些接口都不是其本身的方法,而是通过接口的方式,必须addListener进去才可以。
9. 线程间通信 EventHandler 有点类似Android上的Handler 可以进行线程间通信
10. 列表布局:ListContainer 列表对于ListView
11. 布局文件解析: LayoutScatter 对应Android LayoutInflate
用法如下:
Component component = LayoutScatter.getInstance(context)
.parse(ResourceTable.Layout_custom_common_dialog, null, false);
12. xml文件存储:Preference 对应Android上 SharedPreference 用法如下:
DatabaseHelper mHelper = new DatabaseHelper(mContext);
Preferences mPreferences = mHelper.getPreferences(sp.xml);
13. 显示设备属性: DisplayAttributes:对应Android 上 DisplayMetrics
获取显示设备的宽高等属性:
DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes();
attributes.densityPixels;
14. 包管理: IBundleManager 对应Android上PackageManager 获取应用包相关属性 用法如下:
IBundleManager bundleManager = context.getBundleManager();
bundleManager.getApplicationInfo(s,i,j);
15. 位图: PixelMap 对应Android上的Bitmap,用于位图显示操作
ImageSource 用于位图的解析,类似于BitmapFactory.decodeXXX,用法如下:
public class PixelMapUtils {
public static PixelMap decodePixelMap(String path) {
try {
ImageSource imageSource = ImageSource.create(path, null);
return imageSource.createPixelmap(null);
} catch (Exception e) {
e.printStackTrace();
LogUtils.error("PixelMapUtils", e.getMessage());
}
return null;
}
public static PixelMap decodePixelMap(String path, int width, int height) {
try {
ImageSource imageSource = ImageSource.create(path, null);
ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
options.desiredSize = new Size(width, height);
return imageSource.createPixelmap(options);
} catch (Exception e) {
e.printStackTrace();
LogUtils.error("PixelMapUtils", e.getMessage());
}
return null;
}
}
16. 弹窗:CommonDialog 类似Android AlertDialog
四、鸿蒙原子化服务卡片开发
原子化服务是HarmonyOS提供的一种面向未来的服务提供方式,是有独立入口的(用户可通过点击方式直接触发)、免安装的(无需显式安装,由系统程序框架后台安装后即可使用)、可为用户提供一个或多个便捷服务的用户应用程序形态。
简单来说,轻量级鸿蒙应用,免手动安装,无桌面图标,由鸿蒙服务中心管理,大小限制10M以内,api使用和应用一样。用户第一次在服务中心点击的时候会下载应用后台自动安装。
服务中心入口是在鸿蒙手机桌面左下角上滑就能出现。服务中心展示如下。
分类:
原子化服务卡片有两种类型,java卡片和js卡片。
java卡片:就是用以xml布局,java逻辑控制的卡片。
js卡片: 以JS显示布局界面。
卡片运作机制:
基本概念:
-
卡片提供方(也就是我们的服务卡片应用)
提供卡片显示内容的HarmonyOS应用或原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。
-
卡片使用方(主要是鸿蒙桌面以及服务中心)
显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
-
卡片管理服务(这个就是鸿蒙的系统服务了)
用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。
生命周期时序:
卡片不是独立存在的,必须依托在Ability之内,其生命周期方法都实现在Ability内
同卡片通信以及更新卡片
详情见:developer.harmonyos.com/cn/docs/doc…
js卡片和java卡片通信方式不太一样,此处介绍js卡片,java卡片可以详细看文档。
卡片其实有点类似于android以及ios桌面widget一样。实际上和卡片通信其实也是个跨进程过程。
@Override
public void updateFormData(long formId, Object... vars) {
Resource resourceImageSrc = null;
try {
resourceImageSrc = context.getResourceManager().getResource(ResourceTable.Media_beauty);
byte[] bytesImageSrc = imageConvertToByteArray(resourceImageSrc);
ZSONObject zsonObject = new ZSONObject();
String fileName = "ic_image_"+System.currentTimeMillis() +".png";
zsonObject.put("picture", "memory://" + fileName); // 通过这个zsonObject 的key值要和index.json文件中的data对应
FormBindingData formBindingData = new FormBindingData(zsonObject);
formBindingData.addImageData(fileName, bytesImageSrc);
try {
((Ability) context).updateForm(formId, formBindingData);
} catch (FormException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (NotExistException e) {
e.printStackTrace();
}
}
通信借助FormBindingData 这个序列化的类,可以通过json 传递普通数据。也可以通过addImageData接口添加图片字节数组。
通过字节数组传递进去的图片,路径为json中"picture"对应的value值,此处必须为memory:// 开头表示传递进去的内存数据。
每次更新图片路径必须变更,否则会导致更新不了,所以这里采用当前时间加到图片路径中。
卡片事件和Action
JS卡片支持为组件设置action,包括router事件和message事件,其中router事件用于应用跳转,message事件用于卡片开发人员自定义点击事件。 关键步骤说明如下:
- 在hml中为组件设置onclick属性,其值对应到json文件的actions字段中。
- 若设置router事件,则
- action属性值为"router";
- abilityName为卡片提供方应用的跳转目标Ability名;
- params中的值按需填写,其值在使用时通过intent.getStringParam("params")获取即可;
- 若设置message事件,则action属性值为"message",params为json格式的值。
后台运行
后台任务调度,详情可看developer.harmonyos.com/cn/docs/doc…
应用如果需要常驻后台运行,需要配置后台运行模式,以及配置后台运行权限。鸿蒙这边有规范,特定分类的应用才允许设置相应后台模式,否则不允许上架。
后台模式分类 HarmonyOS提供了十种后台模式,供需要在后台做长驻任务的业务使用。
具体的后台模式类型如下:
| 长驻任务后台模式 | 英文名 | 描述 |
|---|---|---|
| 数据传输 | data-transfer | 通过网络/对端设备进行数据下载、备份、分享、传输等业务 |
| 播音 | audio-playback | 音频输出业务 |
| 录音 | audio-recording | 音频输入业务 |
| 画中画 | picture-in-picture | 画中画、小窗口播放视频业务 |
| 音视频通话 | voip | 音视频电话,VoIP业务 |
| 导航/位置更新 | location | 定位、导航业务 |
| 蓝牙设备连接及传输 | bluetooth-interaction | 蓝牙扫描、连接、传输业务 |
| WLAN设备连接及传输 | wifi-interaction | WLAN扫描、连接、传输业务 |
| 屏幕抓取 | screen-fetch | 录屏、截屏业务 |
| 多设备互联 | multiDeviceConnection | 多设备互联,分布式调度和迁移等业务 |
折叠屏适配
详细配置步骤参照平行视界开发指导:平行视界开发指导
根据鸿蒙给的建议,以经验值:屏幕像素宽度大于1440认为是折叠屏的展开状态。
首先在针对需要适配的Ability增加如下configChanges属性,避免这些属性变化导致Ability重启。因为折叠屏展开关闭会导致屏幕size变化
然后重写Ability的onConfigurationUpdated方法。图片
public class MainAbility extends Ability {
private Size currentSize;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
setUIContent(getLayoutResId());
getWindow().setStatusBarColor(RgbPalette.parse("#F5f5f5"));
getWindow().setBackgroundColor(RgbColor.fromArgbInt(RgbPalette.parse("#F5f5f5")));
currentSize = ScreenUtils.getScreenSize();
if (currentSize.width > 1440) {
// 是折叠屏,界面如果需要不一样的话,就在此处设置
}
}
@Override
public void onConfigurationUpdated(Configuration configuration) {
super.onConfigurationUpdated(configuration);
Size size = ScreenUtils.getScreenSize();
// 屏幕尺寸发生变化
if (currentSize.width != size.width || currentSize.height != size.height) {
currentSize = size;
// 大于1440 就是折叠屏的展开状态
if (ScreenUtils.getScreenSize().width > ScreenUtils.THRESHOLD_WIDTH) {
// 展开下,界面布局参数修改
} else {
// 折叠态,界面布局参数修改
}
}
}
}
五、鸿蒙第三方库
目前鸿蒙已经实现的常用三方库列表:www.cnblogs.com/HarmonyOS/p…
鸿蒙开源三方库git仓库:gitee.com/openharmony…
鸿蒙技术社区:harmonyos.51cto.com/
六、总结
文章仅是本人第一次从0学习搭建鸿蒙的一份总结,主要旨在让大家对鸿蒙开发有一个整体的认识,一些技术细节,最好对照官方详细文档。有问题大家可以一起学习。