鸿蒙开发初体验(Android开发必看)

2020年9月10号,鸿蒙2.0(HarmonyOS 2.0)系统正式发布,鸿蒙2.0面向应用开发者发布Beta版本,在2020年9月10发布大屏,手表,车机版鸿蒙,2020年12月发布手机版鸿蒙。在2020年9月10日,鸿蒙开源路标面向内存128KB-128MB终端设备;2021年10月,将面向4GB以上所有设备。

背景

作为一个安卓开发者,能够看到国产的操作系统的发布确实很兴奋,兴奋之余,更想要看看具体是怎么一回事,首先打开官网,看看官网该系统的定义:HarmonyOS是一款“面向未来”、面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持多种终端设备。

对应用开发者而言,HarmonyOS采用了多种分布式技术,使得应用程序的开发实现与不同终端设备的形态差异无关,降低了开发难度和成本。这能够让开发者聚焦上层业务逻辑,更加便捷、高效地开发应用。该优点在5G这个万物互联的时代具有着巨大的优势。

安装DevEco Studio

接下来下载DevEco Studio(IDE/开发工具)来进行体验一下软件的开发,在这里可以看到目前的IDE只有Windows系统的(windows 10 64位),安装过程可能中会出现gradle的安装失败,记得添加代理,在用户目录(打开“此电脑”,在文件夹地址栏中输入%userprofile%,进入个人数据界面。)下创建gradle.properties文件,文件中添加,端口是代理的端口

systemProp.https.proxyPort=63729
systemProp.http.proxyHost=127.0.0.1
systemProp.https.proxyHost=127.0.0.1
systemProp.http.proxyPort=63729
复制代码

gradle安装成功,但在编译过程中可能出现build失败,错误如下:

ERROR: Cause: mirrors.huaweicloud.com:443 failed to respond
复制代码

解决方式就是把所有的代理先关掉,然后你就会发现如丝般顺滑。

安装完DevEco Studio后,打开后可以看到界面和Android Studio非常相似

1.布局开发

一切看起来非常的熟悉,可以使用Java或JS等语言进行开发,布局可以通过XML创建,size单位是vp

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:orientation="vertical"
    ohos:padding="32">
    <Text
        ohos:id="$+id:text"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="My name is Jackie."
        ohos:text_size="25vp"/>
    <Button
        ohos:id="$+id:button"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="My name is Jackie."
        ohos:text_size="50"/>
</DirectionalLayout>
复制代码

也可以通过Java代码直接创建,点击事件都是如此的亲切

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    // 步骤1 声明布局
    DirectionalLayout directionalLayout = new DirectionalLayout(context);
    // 步骤2 设置布局大小
    directionalLayout.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
    directionalLayout.setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
    // 步骤3 设置布局属性及ID(ID视需要设置即可)
    directionalLayout.setOrientation(Component.VERTICAL);
    directionalLayout.setPadding(32, 32, 32, 32);

    Text text = new Text(context);
    text.setText("My name is Text.");
    text.setTextSize(50);
    text.setId(100);
    // 步骤4.1 为组件添加对应布局的布局属性
    DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT,
        LayoutConfig.MATCH_CONTENT);
    layoutConfig.alignment = LayoutAlignment.HORIZONTAL_CENTER;
    text.setLayoutConfig(layoutConfig);

    // 步骤4.2 将Text添加到布局中
    directionalLayout.addComponent(text);

    // 类似的添加一个Button
    Button button = new Button(context);
    layoutConfig.setMargins(0, 50, 0, 0);
    button.setLayoutConfig(layoutConfig);
    button.setText("My name is Jackie.");
    button.setTextSize(50);
    button.setId(100);
    ShapeElement background = new ShapeElement();
    background.setRgbColor(new RgbColor(0, 125, 255));
    background.setCornerRadius(25);
    button.setBackground(background);
    button.setPadding(10, 10, 10, 10);
    button.setClickedListener(new Component.ClickedListener() {
        @Override
        // 在组件中增加对点击事件的检测
        public void onClick(Component Component) {
            // 此处添加按钮被点击需要执行的操作
        }
    });
    directionalLayout.addComponent(button);

    // 步骤5 将布局作为根布局添加到视图树中
    super.setUIContent(directionalLayout);
}
复制代码

首页的布局如下,通过Java代码创建

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        System.out.println("onStart");
        LayoutConfig config = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT);
        myLayout.setLayoutConfig(config);
        ShapeElement element = new ShapeElement();
        element.setRgbColor(new RgbColor(255, 255, 255));
        myLayout.setBackground(element);

        Text text = new Text(this);
        text.setLayoutConfig(config);
        text.setText("CT Jackie");
        text.setTextColor(new Color(0xFF000000));
        text.setTextSize(50);
        text.setTextAlignment(TextAlignment.CENTER);
        myLayout.addComponent(text);
        super.setUIContent(myLayout);
    }
复制代码

效果如下:

2.生命周期

下面再来看看主界面的生命周期,实现了ILifecycle接口,生命周期状态一共有七种

public static enum Event {
        UNDEFINED,
        ON_START,
        ON_INACTIVE,
        ON_ACTIVE,
        ON_BACKGROUND,
        ON_FOREGROUND,
        ON_STOP;
        private Event() {
        }
    }
复制代码

界面启动时调用onStart()和onActive()

2020-09-13 21:42:10.266 25547-25547[表情] I/System.out: onStart
2020-09-13 21:42:10.284 25547-25547[表情] I/System.out: onActive
复制代码

点击返回键时调用

2020-09-13 21:42:35.847 25547-25547/com.example.helloworld I/System.out: onInactive
2020-09-13 21:42:35.917 25547-25547/com.example.helloworld I/System.out: onBackground
2020-09-13 21:42:35.920 25547-25547/com.example.helloworld I/System.out: onStop
复制代码

至于UNDEFINED和ON_FOREGROUND暂时还不了解。

3.Gradle任务(Task)

甚至连gradle的Task都非常类似,打包命令是assembleDebug/Release

> Task :entry:preBuild
> Task :entry:compileDebugNativeWithCmake
> Task :entry:collectDebugDependencies
> Task :entry:mergeDebugResources
> Task :entry:mergeDebugProfile
> Task :entry:compileDebugResources
> Task :entry:compileDebugIdl
> Task :entry:compileDebugRFile
> Task :entry:processDebugJavaResource
> Task :entry:compileDebugJavaWithJavac
> Task :entry:mergeDebugJavaResource
> Task :entry:generateDebugClassesJar
> Task :entry:mergeDebugProjectDex
> Task :entry:generateDebugShell
> Task :entry:processDebugShellManifest
> Task :entry:compileDebugShellResources
> Task :entry:linkDebugShellResources
> Task :entry:compileDebugShellJavaWithJavac
> Task :entry:mergeDebugShellDex
> Task :entry:packageDebugShell
> Task :entry:packageDebugSimplifyShell
> Task :entry:validateDebugSigning
> Task :entry:signDebugShell
> Task :entry:packageDebugHap
> Task :entry:signDebugHap
> Task :entry:assembleDebug
复制代码
4.配置文件

配置文件是一个命名为config.json的文件,配置应用的一些信息

{
  "app": {
    "bundleName": "com.example.helloworld",
    "vendor": "example",
    "version": {
      "code": 1,
      "name": "1.0"
    },
    "apiVersion": {
      "compatible": 3,
      "target": 3
    }
  },
  "deviceConfig": {
    "default": {

    }
  },
  "module": {
    "package": "com.example.helloworld",
    "name": ".HelloWorld",
    "reqCapabilities": [
      "video_support"
    ],
    "deviceType": [
      "wearable"
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry"
    },
    "abilities": [
      {
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ],
        "orientation": "landscape",
        "formEnabled": false,
        "name": "com.example.helloworld.MainAbility",
        "icon": "$media:icon",
        "description": "$string:mainability_description",
        "label": "HelloWorld",
        "type": "page",
        "launchType": "standard"
      }
    ]
  }
}
复制代码

仔细看这个文件会越来越觉得这就是AndroidManifest.xml的json翻译版。

反编译角度看鸿蒙

既然看起来这么像安卓,我看来看看它编译后的产物是什么,是不是也能像android一样反编译得到dex文件?

编译后得到的是一个xxx.hap文件

修改它的后缀名为.zip,解压后可以看到里面有熟悉的assets,dex,apk文件等,把这个apk文件安装后发现并不能使用。

下面我们先反编译这个classes.dex文件第一个dex反编译后出现错误

~/Desktop/fanbianyi/dex2jar-2.0 » sh d2j-dex2jar.sh classes3.dex
dex2jar classes3.dex -> ./classes3-dex2jar.jar
com.googlecode.d2j.DexException: not support version.
    at com.googlecode.d2j.reader.DexFileReader.<init>(DexFileReader.java:151)
    at com.googlecode.d2j.reader.DexFileReader.<init>(DexFileReader.java:211)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:104)
    at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:288)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:32)
复制代码

原因是我们的工具版本太低了,解决方案在这,升级版本后反编译成功后为classes3-dex2jar.jar,打开可以看到

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

这里多了个ResourceTable文件,就是我们的资源id表。这里的dex文件包含的是我们开发的代码。

下面我们来反编译apk文件,解压后可以看到,里面是我们熟悉的内容

AndroidManifest.xml文件如下

反编译该dex文件可以看到,MainAbilityShellActivity最终是继承了AbilityShellActivity

ShellHelloWorld其实一个Application

至此感觉.hap文件像是对apk的一个包装,最终的逻辑看起来好像还是android那套,或者说android开发人员上手会非常快,可能也是为将来兼容android系统做准备。

分布式,跨设备迁移

跨设备迁移

下面来看看该系统的一些亮点,比如跨设备迁移,听起来是个很牛逼炫酷的功能,比如把你的手机屏幕直接迁移到电脑或者pad上面以及进行一些操作等等

跨设备迁移(下文简称“迁移”)支持将Page在同一用户的不同设备间迁移,以便支持用户无缝切换的诉求。以Page从设备A迁移到设备B为例,迁移动作主要步骤如下:

  1. 设备A上的Page请求迁移。
  2. HarmonyOS处理迁移任务,并回调设备A上Page的保存数据方法,用于保存迁移必须的数据。
  3. HarmonyOS在设备B上启动同一个Page,并回调其恢复数据方法。

开发者可以参考以下详细步骤开发具有迁移功能的Page。

分布式任务调度

在HarmonyOS中,分布式任务调度平台对搭载HarmonyOS的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力基线、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。

分布式任务调度平台在底层实现 Ability

  • 启动和关闭:向开发者提供管理远程Ability的能力,即支持启动Page模板的Ability,以及启动、关闭Service和Data模板的Ability。
  • 连接和断开连接:向开发者提供跨设备控制服务(Service和Data模板的Ability)的能力,开发者可以通过与远程服务连接及断开连接实现获取或注销跨设备管理服务的对象,达到和本地一致的服务调度。
  • 迁移能力:向开发者提供跨设备业务的无缝迁移能力,开发者可以通过调用Page模板Ability的迁移接口,将本地业务无缝迁移到指定设备中,打通设备间壁垒。

总结

个人感觉鸿蒙的开发是很接近Android开发者的习惯,对于Android开发人员来说极易上手,但是Android现有的多设备协同支持做的很差,鸿蒙做了一些封装和扩展屏蔽掉底层的差异,在多设备,万物互联的时代具有很大的优势,越是多设备协同,鸿蒙越具有优势。

作者:伤心的猪大肠
链接:https://juejin.im/post/6871999738720288781

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342