DEV Community

ZHZL-m
ZHZL-m

Posted on

【Journey of HarmonyOS Next】Developing with ArkTS (1) - > Ability Development 1

Image description

1 -> Review of FA models

1.1 -> Overall Architecture

The development of HarmonyOS user programs is essentially the development of abilities. The HarmonyOS system manages the life cycle of an ability by combining it with the consistent scheduling contract provided by the system to schedule user programs.

The Ability framework uses the FA model in API 8 and earlier versions. In the FA model, Ability is divided into several types: PageAbility, ServiceAbility, DataAbility, and FormAbility.

PageAbility is a Ability implemented by ArkUI, which is an instance of Ability that is visible to users and can interact with.
ServiceAbility is also a type of Ability, but it does not have a UI and provides other Capabilities to call custom services and run in the background.
DataAbility is also a Ability without UI, which provides other Ability to add, delete, and query data, running in the background.
FormAbility is a form of card ability, which is a form of interface display.

1.2 -> Application package structure

Image description

1.3 -> Life cycle

Of all the Abilities, the PageAbility has a more complex lifecycle because it has an interface and is also the interface for the application.

The following figure shows the PageAbility lifecycle callback:

Image description

For more information about the lifecycle of other types of Ability, see PageAbility Lifecycle: Removing Front-End and Backend Switching, and OnShow for details. You can override the lifecycle function in app.js/app.ets to handle the application logic within the corresponding lifecycle function. Currently, only onCreate and onDestroy callbacks are supported in the app.js environment, and full lifecycle callbacks are supported in the app.ets environment.

1.4 -> Process threading model

The application process is created when the ability is started for the first time, and a thread is created for the ability to start, and after the application is started, other abilities in the application are started, and corresponding threads are created for each ability. Each Ability is bound to a separate JSRuntime instance, so the Abilities are isolated from each other.

Image description

2 -> PageAbility开发

2.1 -> Overview

2.1.1 - Introduction to > features

PageAbility is a Ability with ArkUI implementation, which is an instance of Ability that developers can see and interact with. When you create an ability through an IDE, the IDE automatically creates the template code. PageAbility-related capabilities are implemented through a separate featureAbility, and lifecycle-related callbacks are implemented through each callback function in app.js/app.ets.

2.1.2 -> Lifecycle of PageAbility

PageAbility(Ability Life Cycle):

The lifecycle of a PageAbility is a general term for the states in which a PageAbility is scheduled to various states, such as INACTIVE, ACTIVE, and BACKGROUND.

Image description

Ability Lifecycle Status Description:

UNINITIALIZED:未初始状态,为临时状态,PageAbility被创建后会由UNINITIALIZED状态进入INITIAL状态。

INITIAL: the initialization state, also known as the stopped state, indicates that the current PageAbility is not running, and the PageAbility enters the ACTIVE state from the INITIAL state after it is started.

INACTIVE: LOSES FOCUS, INDICATING THAT THE CURRENT WINDOW IS DISPLAYED BUT HAS NO FOCUS.

ACTIVE: The foreground is active, indicating that the current window is displayed and the focus is obtained.

BACKGROUND: indicates that the current PageAbility has retreated to the background, and the PageAbility has changed from the BACKGROUND state to the INITIAL state after it has been destroyed, or from the BACKGROUND state to the ACTIVE state after it has been reactivated.

Image description

PageAbility provides lifecycle callbacks, and developers can override lifecycle-related callback functions in app.js/app.ets. Currently, only onCreate and onDestroy callbacks are supported in the app.js environment, and full lifecycle callbacks are supported in the app.ets environment.

2.1.3 -> Boot mode

Ability supports both single-instance and multi-instance launch modes.

You can use the launchType configuration item in the config.json to configure the specific startup mode.

Image description

By default, it is singleton mode.

2.2 -> featureAbility

Image description

2.3 -> Start the local PageAbility

Import the module

  import featureAbility from '@ohos.ability.featureAbility'
Enter fullscreen mode Exit fullscreen mode

example

import featureAbility from '@ohos.ability.featureAbility'
featureAbility.startAbility({
    want:
    {
        action: "",
        entities: [""],
        type: "",
        options: {
            // Grant the permission to perform read operations on the URI.
            authReadUriPermission: true,
            // Grant the permission to perform write operations on the URI.
            authWriteUriPermission: true,
            // support forwarding the Want result to the ability.
            abilityForwardResult: true,
            // Enable ability continuation.
            abilityContinuation: true,
            // Specify that a component does not belong to ohos.
            notOhosComponent: true,
            // Specify that an ability is started.
            abilityFormEnabled: true,
            // Grant the permission for possible persisting on the URI.
            authPersistableUriPermission: true,
            // Grant the permission for possible persisting on the prefix URI.
            authPrefixUriPermission: true,
            // Support distributed scheduling system startup on multiple devices.
            abilitySliceMultiDevice: true,
            // A service ability is started regardless of whether the host application has been started.
            startForegroundAbility: true,
            // Install the specified ability if it is not installed.
            installOnDemand: true,
            // Return the result to the ability slice.
            abilitySliceForwardResult: true,
            // Install the specified ability with background mode if it is not installed.
            installWithBackgroundMode: true
        },
        deviceId: "",
        bundleName: "com.example.startability",
        abilityName: "com.example.startability.MainAbility",
        uri: ""
    },
});
Enter fullscreen mode Exit fullscreen mode

The want parameter can also be entered as a key-value parameter.

example

import featureAbility from '@ohos.ability.featureAbility'
featureAbility.startAbility({
    want:
    {
        bundleName: "com.example.startability",
        uri: "",
        parameters: {
            abilityName: "com.example.startability.MainAbility"
        }
    },
});
Enter fullscreen mode Exit fullscreen mode

2.4 -> Lifecycle Interface Description

Image description

example

You need to rewrite the relevant lifecycle callback functions in app.js/app.ets, and the IDE template generates onCreate() and onDestroy() methods by default, and other methods need to be implemented by yourself.

export default {
  onCreate() {
    console.info('Application onCreate')
  },
  onDestroy() {
    console.info('Application onDestroy')
  },
  onShow(){
    console.info('Application onShow')
  },
  onHide(){
    console.info('Application onHide')
  },
  onInactive(){
    console.info('Application onInactive')
  },
  onActive(){
    console.info('Application onActive')
  },
}
Enter fullscreen mode Exit fullscreen mode

3 -> ServiceAbility开发

3.1 -> Scenario Introduction

Ability based on the Service template is mainly used for background running tasks (such as performing music playback and file downloading), but does not provide a user interface. The Service can be started by another application or Ability, and will continue to run in the background even if the user switches to another application.

3.2 -> Interface Description

Image description

3.3 -> Development steps

3.3.1 -> Create Service

  1. Service is also a kind of Ability, and Ability provides the following lifecycle methods for Service, which developers can override to add other Ability requests to handle when interacting with Service Ability.

The following is an example of how to create a Service:

export default {
    onStart() {
        console.log('ServiceAbility onStart');
    },
    onCommand(want, startId) {
        console.log('ServiceAbility onCommand');
    },
    onConnect(want) {
        console.log('ServiceAbility OnConnect');
        return new FirstServiceAbilityStub('test');
    },
    onDisconnect(want) {
        console.log('ServiceAbility OnDisConnect');
    },
    onStop() {
        console.log('ServiceAbility onStop');
    },
}
Enter fullscreen mode Exit fullscreen mode
  1. Register service

Service also needs to be registered in the application configuration file config.json, and the registration type needs to be set to service.

 {
     "module": {
         "abilities": [         
             {    
                 "name": ".ServiceAbility",
                 "type": "service",
                 "visible": true
                 ...
             }
         ]
         ...
     }
     ...
 }
Enter fullscreen mode Exit fullscreen mode

3.3.2 -> Start Service

Ability provides the developer with the startAbility() method to start another Ability. Since a Service is also a type of Ability, developers can also start a Service by passing a Want to this method.

Developers can construct a Want object containing bundleName and abilityName to set the target service information. The parameters are defined as follows:

bundleName:Package name。
abilityName: indicates the name of the ability to be started.

import featureAbility from '@ohos.ability.featureAbility';
let promise = featureAbility.startAbility(
    {
        want:
        {
            bundleName: "com.jstest.service",
            abilityName: "com.jstest.service.ServiceAbility",
        },
    }
); 
Enter fullscreen mode Exit fullscreen mode

After executing the above code, the Ability will start the Service via the startAbility() method.

If the Service is not yet running, the system will call onStart() to initialize the Service, and then call back the onCommand() method of the Service to start the Service.
If the Service is running, the system will directly call back the onCommand() method of the Service to start the Service.

3.3.3 -> 停止Service

Once a Service is created, it remains running in the background and will not be stopped or destroyed unless memory resources must be reclaimed. Developers can stop the Service by terminateSelf() in the Service.

3.3.4 -> Connect to the local Service

If a Service needs to interact with a Page Ability or a Service Ability of another application, it must create a Connection for the connection. The Service allows other Abilities to connect to it via the connectAbility() method.

When using connectAbility() to process callbacks, you need to pass in the Want and IAbilityConnection instances of the target Service. IAbilityConnection provides the following methods for developers to implement: onConnect() is used to handle the callback of successfully connecting to the Service, onDisconnect() is used to handle the callback of the Service abnormal death, and onFailed() is used to handle the callback of the failure to connect to the Service.

import prompt from '@system.prompt'

var option = {
    onConnect: function onConnectCallback(element, proxy) {
        console.log(`onConnectLocalService onConnectDone`)
        if (proxy === null) {
            prompt.showToast({
                message: "Connect service failed"
            })
            return
        }
        let data = rpc.MessageParcel.create()
        let reply = rpc.MessageParcel.create()
        let option = new rpc.MessageOption()
        data.writeInterfaceToken("connect.test.token")
        proxy.sendRequest(0, data, reply, option)
        prompt.showToast({
            message: "Connect service success"
        })
    },
    onDisconnect: function onDisconnectCallback(element) {
        console.log(`onConnectLocalService onDisconnectDone element:${element}`)
        prompt.showToast({
            message: "Disconnect service success"
        })
    },
    onFailed: function onFailedCallback(code) {
        console.log(`onConnectLocalService onFailed errCode:${code}`)
        prompt.showToast({
            message: "Connect local service onFailed"
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

The following is an example of the code that connects to a local service:

import featureAbility from '@ohos.ability.featureAbility';
let connId = featureAbility.connectAbility(
    {
        bundleName: "com.jstest.service",
        abilityName: "com.jstest.service.ServiceAbility",
    },
    {
        onConnect: onConnectCallback,
        onDisconnect: onDisconnectCallback,
        onFailed: onFailedCallback,
    },
);
Enter fullscreen mode Exit fullscreen mode

At the same time, the Service side also needs to return an IRemoteObject when onConnect() to define the interface to communicate with the Service. onConnect() needs to return an IRemoteObject object, and HarmonyOS provides a default implementation of IRemoteObject, which can be used by inheriting rpc. RemoteObject to create a custom implementation class.

The following is an example of the code for the Service side to return its own instance to the calling side:

import rpc from "@ohos.rpc";

class FirstServiceAbilityStub extends rpc.RemoteObject {
constructor(des: any) {
    if (typeof des === 'string') {
        super(des)
    } else {
        return
    }
}

onRemoteRequest(code: number, data: any, reply: any, option: any) {
    console.log(printLog + ` onRemoteRequest called`)
    if (code === 1) {
        let string = data.readString()
        console.log(printLog + ` string=${string}`)
        let result = Array.from(string).sort().join('')
        console.log(printLog + ` result=${result}`)
        reply.writeString(result)
    } else {
        console.log(printLog + ` unknown request code`)
    }
    return true;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)