Recently (4.12 ~ 4.25), Hongmon OS is holding a developer day, take the opportunity to attend and learn about the current situation and application development experience of Hongmon OS. Developer.huawei.com/consumer/cn…
1. Development environment construction
Download and install the IDE (current version 2.1 Beta3)
Huawei provides an IDE for Harmony app development: DevEco Studio (I don’t like the Eco name, but IT doesn’t matter how PPT is used, can we be practical with development tools?).
You need to log in to Huawei to download the IDE. I installed the Mac version, and the installation process was relatively smooth after downloading
The launch screen shows that DevEco Studio is still a custom IDE based on IntelliJ
Download the SDK
As with Android, the first thing to do when the IDE starts is to download the Harmony SDK
Each version of the SDK provides three sets of apis for developing Java, Js, and C++ code, which need to be consistent across versions. Different huawei devices have different requirements for SDK versions. For example, in the test, it was found that my API4 code could not run on P40, so it was OK to change to API5
About the SDK source code
Note that it is currently not possible to download the source code as a package through SDKManager. The source code needs to be downloaded separately through Gitee
gitee.com/openharmony
This makes it difficult to debug the code, and I wonder if the source code can be packaged with the SDK like Andoird
Create a project
Harmony is a multi-terminal collaboration, so it is very important to diversify the devices, and can create template projects for different devices
Compared to AndroidStudio, Harmony provides a much richer project template. In addition to the UI, the template also provides some data layer code, which is basically a secondary development APP.
2. Hongmeng Project Structure
The IDE interface
Create a template project for News Feature Ability and successfully open it in the IDE:
The Preview window on the right side of Harmony provides a Preview of XML or Ablitiy files, a bit of a Compose Preview feeling, but only static Preview, not interactive
Engineering documents
Project files are similar to Android, and even one-to-one relationships can be found
Harmony | Android | instructions |
---|---|---|
entry | app | The default startup module (main module) is equivalent to app_module |
MyApplication | XXXApplication | Hongmeng’s MyApplication isAbilityPackage A subclass of |
MainAbility | MainActivity | Entry page. Hongmengzhong unified the concept of four components intoAbility |
MainAbilityListSlice | XXXFragment | Slice Like fragments, the basic building block of UI |
Component | View | Component The class is equivalent to View, as described later |
config.json | AndroidManifest.xml | Hongmeng uses JSON instead of XML for Manifest configuration, and the configuration project is similar |
resources/base/… | res/… | All resource files, including Layout files, still use XML |
resources/rawfile/ | assets/ | Rawfile stores raw resources in any format, equivalent to assets |
build.gradle | build.gradle | Compile the script, same thing |
build/outpus/… /*.hap | build/outputs/… /*.apk | Hongmeng’s product ishap(harmony application package) There’s an.apk file with the same name, This followed because Hongmeng needed a compatible solution that also supported APK installations |
Ability
Ability is an abstraction of what an application is capable of, and Harmony allows applications to be deployed in units of Ability. An application consists of one or more FA (Feature Ability) or PA (Particle Ability). FA has a UI interface to provide the ability to interact with users; While PA has no UI interface, it provides the ability to run tasks in the background and a unified data access abstraction
- FA supports Page Ability:
- Page Ability is used to provide the Ability to interact with the user. A Page can be composed of one or more AbilitySlice, AbilitySlice between the Page navigation
- PA supports Service Ability and Data Ability:
- Service Ability: Provides the Ability to run tasks in the background.
- Data Ability: Used to provide a uniform Data access abstraction to the outside world.
There is a sense that Ability can be understood against the four components of Android
Harmony | Android |
---|---|
Page Ability (FA) | Activity |
Service Ability (PA) | Service |
Data Ability (PA) | ContentProvider |
AbilitySlice | Fragment |
The code in
MainAbility
Take the preset News Feature Ability as an example, which is a Page Ability with two slices, registering two slices through the Router
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilityListSlice.class.getName()); // Add route: ListSlice
addActionRoute("action.detail", MainAbilityDetailSlice.class.getName());//DetailSlice. }}Copy the code
Here is the page effect of running two slices in the emulator
MainAbilityListSlice | MainAbilityDetailSlice |
---|---|
MainAbilityListSlice
Look at the display logic of the list
public class MainAbilityListSlice extends AbilitySlice {...@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_news_list_layout);
initView();
initData(); // Load the data
initListener();
newsListContainer.setItemProvider(newsListAdapter); // Set Adatper to View
newsListAdapter.notifyDataChanged(); // Refresh the data
}
private void initListener(a) {
newsListContainer.setItemClickedListener((listContainer, component, i, l) -> {
// Route jump "action.detail"
LogUtil.info(TAG, "onItemClicked is called");
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withBundleName(getBundleName())
.withAbilityName("com.example.myapplication.MainAbility")
.withAction("action.detail")
.build();
intent.setOperation(operation);
startAbility(intent);
});
}
private void initData(a) {... totalNewsDatas =new ArrayList<>();
newsDatas = new ArrayList<>();
initNewsData();/ / fill newsDatas
newsListAdapter = new NewsListAdapter(newsDatas, this);// Set to Adapter}... }Copy the code
Similar to ListView usage, data is loaded through Adatper; MainAbilityDetailSlice is skipped by route in setItemClickedListener.
The Layout_news_list_layout file is defined as follows. ListContainer, or ListView, is a subclass of Comopnent, and Component is the View in HarmonyOS
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:selector_list"
ohos:height="40vp"
ohos:width="match_parent"
ohos:orientation="horizontal"
/>
<Component
ohos:height="0.5 the vp"
ohos:width="match_parent"
ohos:background_element="#EAEAEC"
/>
<ListContainer
ohos:id="$+id:news_container"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
Copy the code
Take a look at the Adapter implementation, which inherits from BaseItemProvider
/** * News list adapter */
public class NewsListAdapter extends BaseItemProvider {
private List<NewsInfo> newsInfoList;
private Context context;
public NewsListAdapter(List<NewsInfo> listBasicInfo, Context context) {
this.newsInfoList = listBasicInfo;
this.context = context;
}
@Override
public int getCount(a) {
return newsInfoList == null ? 0 : newsInfoList.size();
}
@Override
public Object getItem(int position) {
return Optional.of(this.newsInfoList.get(position));
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int position, Component componentP, ComponentContainer componentContainer) {
ViewHolder viewHolder = null;
Component component = componentP;
if (component == null) {
component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_news_layout, null.false);
viewHolder = new ViewHolder();
Component componentTitle = component.findComponentById(ResourceTable.Id_item_news_title);
Component componentImage = component.findComponentById(ResourceTable.Id_item_news_image);
if (componentTitle instanceof Text) {
viewHolder.title = (Text) componentTitle;
}
if (componentImage instanceof Image) {
viewHolder.image = (Image) componentImage;
}
component.setTag(viewHolder);
} else {
if (component.getTag() instanceofViewHolder) { viewHolder = (ViewHolder) component.getTag(); }}if (null! = viewHolder) { viewHolder.title.setText(newsInfoList.get(position).getTitle()); viewHolder.image.setScaleMode(Image.ScaleMode.STRETCH); }return component;
}
/** * ViewHolder which has title and image */
private static class ViewHolder { Text title; Image image; }}Copy the code
It’s basically a standard ListAdatper, replacing a View with a Component.
About the Simulator
The code is ready to run in the emulator. A few things to say about the simulator:
-
Harmony’s emulator starts very quickly, without the need to download an image, because the emulator doesn’t run locally, it’s just VNC from a remote device, so it has to be used online, and it loses frames when it’s not smooth enough. Not everyone can afford a P40, though the real thing works better
-
The simulator is embedded in an IDE window (like the Preview window), which is not independent of the window, which causes the problem that when multiple ides are open at the same time, the simulator may be displayed in another IDE (like Logcat off-track).
-
To use the emulator, you have to go through itDeveloper certification, the official recommendation to use bank card authentication. The emulator is connected remotely to a real device, is there a charge for renting the device for the future?Remember to read an article before, if it is from a foreign registered account can use the simulator without authentication, but too lazy to toss about
3. Develop JS applications
In addition to Java, Hongmeng also supports jS-BASED application development and improves its cross-platform capabilities with front-end technology.
Hongmon provides a variety of commonly used UI components for JS project, but it does not use the current mainstream JS components like React and Vue, and is still based on the traditional way of CSS3/HTML5/JS development. The JS engineering structure is as follows
directory | instructions |
---|---|
common | This option is used to store common resource files, such as media resources, custom components, and JS documents |
i18n | This parameter is optional. It is used to store json files in multiple languages |
pages/index/index.hml | The HML file defines the layout structure of the page, the components used, and the hierarchy of those components |
pages/index/index.css | The CSS file defines the style and layout of the page, including style selectors and various style properties |
pages/index/index.js | This file defines all the logical relationships used in the page, such as data, events, and so on |
resources | This option is used to store resource configuration files, such as global style and multi-resolution load configuration files |
app.js | Global JavaScript logic file and application lifecycle management. |
4. Migrate across devices
It may feel like Android, but the best feature of HarmonyOS is its ability to collaborate across devices, such as the ability to move pages seamlessly between devices within the same user.
For example, to migrate Page from device A to device B, perform the following steps:
- Page on device A requests migration.
- HarmonyOS calls back to the save data method of the Page on device A to save the data necessary for the migration.
- HarmonyOS starts the same Page on device B and calls back its recovery method.
The migration is requested by calling continueAbility(). Obtain the device list as follows, and request migration after successful pairing
doConnectImg.setClickedListener(
clickedView -> {
// Get the list of online devices with the FLAG_GET_ONLINE_DEVICE flag
List deviceInfoList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
if (deviceInfoList.size() < 1) {
WidgetHelper.showTips(this."No network equipment");
} else {
DeviceSelectDialog dialog = new DeviceSelectDialog(this);
// Click to migrate to the specified device
dialog.setListener(
deviceInfo -> {
LogUtil.debug(TAG, deviceInfo.getDeviceName());
LogUtil.info(TAG, "continue button click");
try {
// Start task migration
continueAbility();
LogUtil.info(TAG, "continue button click end");
} catch (IllegalStateException | UnsupportedOperationException e) {
WidgetHelper.showTips(this, ResourceTable.String_tips_mail_continue_failed); } dialog.hide(); }); dialog.show(); }});Copy the code
Page migration involves data transfer, which requires communication with an IAbilityContinuation.
IAbilityContinuation for communication across devices
Pages migrating across devices need to implement the IAbilityContinuation interface.
Note: An application may contain multiple pages. You only need to implement the IAbilityContinuation interface in pages that support migration by using the following method. At the same time, this Page contains all AbilitySlice also need to implement this interface.
public class MainAbility extends Ability implements IAbilityContinuation {...@Override
public void onCompleteContinuation(int code) {}
@Override
public boolean onRestoreData(IntentParams params) {
return true;
}
@Override
public boolean onSaveData(IntentParams params) {
return true;
}
@Override
public boolean onStartContinuation(a) {
return true; }}public class MailEditSlice extends AbilitySlice implements IAbilityContinuation {...@Override
public boolean onStartContinuation(a) {
LogUtil.info(TAG, "is start continue");
return true;
}
@Override
public boolean onSaveData(IntentParams params) {... LogUtil.info(TAG,"begin onSaveData:"+ mailData); . LogUtil.info(TAG,"end onSaveData");
return true;
}
@Override
public boolean onRestoreData(IntentParams params) {
LogUtil.info(TAG, "begin onRestoreData"); . LogUtil.info(TAG,"end onRestoreData, mail data: " + cachedMailData);
return true;
}
@Override
public void onCompleteContinuation(int i) {
LogUtil.info(TAG, "onCompleteContinuation"); terminateAbility(); }}Copy the code
-
OnStartContinuation (): After a Page requests a migration, the system first calls back to this method, where the developer can decide whether the migration is currently possible, for example, a pop-up that lets the user confirm whether to start the migration.
-
OnSaveData (): If onStartContinuation() returns true, the system calls back to this method, and in this callback the developer saves data that must be passed to another device to restore the Page state.
-
OnRestoreData (): After the Page has finished saving data on the source device, the system calls back this method on the target device, and the developer receives the data used to restore the Page state in this callback. Note that a Page on the target device restarts its life cycle regardless of how its boot mode is configured. The system calls back to this method before onStart().
-
OnCompleteContinuation (): Once the recovery on the target device is complete, the system calls back this method on the Page on the source device to notify the application that the migration process has ended. This is where the developer can check whether the migration was successful and handle the actions of the end of the migration. For example, the application can terminate its life cycle after the migration is complete.
Take Page migration from device A to device B as an example. The detailed process is as follows:
- Page on device A requests migration.
- The system calls back Page on device A and all AbilitySlice instances in the AbilitySlice stack
IAbilityContinuation.onStartContinuation()
Method to verify whether the migration is currently available immediately. - If the migration is possible immediately, the system calls back all AbilitySlice instances of Page on device A and its AbilitySlice stack
IAbilityContinuation.onSaveData()
Method to save the data necessary to restore state after migration. - If the data is saved successfully, the system starts the same Page on device B, restores the AbilitySlice stack, and then calls back
IAbilityContinuation.onRestoreData()
Method to pass previously saved data; After device B on this Page fromonStart()
Begins its lifecycle callback. - The system calls back Page on device A and all AbilitySlice instances in the AbilitySlice stack
IAbilityContinuation.onCompleteContinuation()
Method to notify the data recovery success.
5. Summary and impressions
- From the SDK to the IDE, it is highly similar to Android, and any Android developer is basically a quasi-developer
- While AndroidStudio is iterating quickly, DevEco Studio still has a significant gap in functionality
- You need to authenticate your real name before you can use the full functionality of the IDE
- The source code requires a separate download and is not debug friendly
- Kotlin is not currently supported. The trend is there, so it will be supported in the future, and the fact that Kotlin is open source is not a problem
- The technical architecture of the JS UI framework is also somewhat outdated
- The killer card is support for multi-end collaboration, but it may take more vendors to really take off
At present, people’s attitudes towards Hongmeng are polarized. Some people adore hongmeng while others devalue it. In my opinion, it is unnecessary to give hongmeng more space and patience, watch its change and enjoy its success. Of course, the first choice needs Huawei to do not take the initiative to hype, really calm down to polish Hongmeng, as long as Huawei is determined and patient, as developers why don’t we support it?
Harmony Online Challenge
Along with the developer activity day, Hongmeng also held several rounds of online challenge activities (still in progress), the difficulty is not high participation can be completed, and the winning rate is high (personal testing), interested can participate, I hope I pass the good luck to you
Event details: mp.weixin.qq.com/s/3IrZGZkm1…
A link to the
- HarmonyOS official www.harmonyos.com/cn/home
- HarmonyOS developer documentation developer.harmonyos.com/cn/document…
- HarmonyOS source gitee.com/openharmony