HarmonyOS/OpenHarmony application development-Stage model UIAbility component use (6)

Interaction between UIAbility components (in-device)

UIAbility is the smallest unit of system scheduling. When jumping between functional modules in the device, it will involve launching a specific UIAbility. The UIAbility can be other UIAbilities in the application or UIAbilities of other applications (for example, launching a three-party payment UIAbility).

This article will introduce the interaction methods between UIAbilities in the device from the following scenarios.

Start the UIAbility within the app. Start the UIAbility in the app and get the returned result. Launch UIAbility for other apps. Start the UIAbility of other apps and get the returned result. Launch the specified page of UIAbility. Realize UIAbility interaction through Call (only open to system applications).

4. Start the UIAbility of other applications and get the returned results

When using the implicit Want to start the UIAbility of another application and want to get the returned result, the caller needs to use the startAbilityForResult() method to start the target UIAbility. For example, the main application needs to start three-party payment and obtain the payment result.

1. In the module.json5 configuration file corresponding to UIAbility of the payment application, configure the entities field and actions field of skills.

{
  "module": {
    "abilities": [
      {
        // ...
        "skills": [
          {
            "entities": [
              // ...
              "entity.system.default"
            ],
            "actions": [
              // ...
              "ohos.want.action.editData"
            ]
          }
        ]
      }
    ]
  }
}

2. The caller uses the startAbilityForResult() method to start the UIAbility of the payment application. The entities and actions in the caller's want parameter need to be included in the entities and actions of the skills configuration to match the UIAbility. The data in the asynchronous callback is used to receive the information returned to the caller after the payment UIAbility stops itself. After the system matches the UIAbility that meets the parameters of entities and actions, a selection box will pop up to display the list of matched UIAbility instances for the user to choose and use.

let wantInfo = {
    deviceId: '', // deviceId为空表示本设备
    // uncomment line below if wish to implicitly query only in the specific bundle.
    // bundleName: 'com.example.myapplication',
    action: 'ohos.want.action.editData',
    // entities can be omitted.
    entities: ['entity.system.default'],
}

// context为调用方UIAbility的AbilityContext
this.context.startAbilityForResult(wantInfo).then((data) => {
    // ...
}).catch((err) => {
    // ...
})

3. After paying UIAbility to complete the payment, you need to call the terminateSelfWithResult() method to stop yourself, and return the abilityResult parameter information to the caller.

const RESULT_CODE: number = 1001;
let abilityResult = {
    resultCode: RESULT_CODE,
    want: {
        bundleName: 'com.example.myapplication',
        abilityName: 'EntryAbility',
        moduleName: 'entry',
        parameters: {
            payResult: 'OKay',
        },
    },
}
// context为被调用方UIAbility的AbilityContext
this.context.terminateSelfWithResult(abilityResult, (err) => {
    // ...
});

3. Receive the information returned by the payment application in the callback of the caller's startAbilityForResult() method. The RESULT_CODE needs to be consistent with the value returned by the previous terminateSelfWithResult()

const RESULT_CODE: number = 1001;

let want = {
  // Want参数信息
};

// context为调用方UIAbility的AbilityContext
this.context.startAbilityForResult(want).then((data) => {
    if (data?.resultCode === RESULT_CODE) {
        // 解析被调用方UIAbility返回的信息
        let payResult = data.want?.parameters?.payResult;
        // ...
    }
}).catch((err) => {
    // ...
})

5. Start the specified page of UIAbility

A UIAbility can correspond to multiple pages. Different pages need to be displayed when starting the UIAbility in different scenarios. For example, when jumping from one UIAbility page to another UIAbility, you want to start the specified page of the target UIAbility. This article mainly explains the two scenarios of starting the specified page when the target UIAbility is started for the first time and the target UIAbility is not started for the first time, and how to specify the startup page on the caller before explaining the startup of the specified page.

( 1) The caller UIAbility specifies the startup page

When the caller UIAbility starts another UIAbility, it usually needs to jump to the specified page. For example, FuncAbility contains two pages (Index corresponds to the home page, and Second corresponds to the function A page). At this time, the specified page path information needs to be configured in the passed-in want parameter, and a custom parameter can be added through the parameters parameter in the want to pass the page jump transfer information. For how to obtain the context in the example, see Obtaining the Context Property of UIAbility.

let wantInfo = {
    deviceId: '', // deviceId为空表示本设备
    bundleName: 'com.example.myapplication',
    abilityName: 'FuncAbility',
    moduleName: 'module1', // moduleName非必选
    parameters: { // 自定义参数传递页面信息
        router: 'funcA',
    },
}
// context为调用方UIAbility的AbilityContext
this.context.startAbility(wantInfo).then(() => {
    // ...
}).catch((err) => {
    // ...
})

( 2) The target UIAbility starts for the first time

When the target UIAbility starts for the first time, in the onWindowStageCreate() lifecycle callback of the target UIAbility, parse the want parameter passed by the EntryAbility, obtain the url of the page information to be loaded, and pass it to the windowStage.loadContent() method.

import UIAbility from '@ohos.app.ability.UIAbility'
import Window from '@ohos.window'

export default class FuncAbility extends UIAbility {
    funcAbilityWant;

    onCreate(want, launchParam) {
        // 接收调用方UIAbility传过来的参数
        this.funcAbilityWant = want;
    }

    onWindowStageCreate(windowStage: Window.WindowStage) {
        // Main window is created, set main page for this ability
        let url = 'pages/Index';
        if (this.funcAbilityWant?.parameters?.router) {
            if (this.funcAbilityWant.parameters.router === 'funA') {
                url = 'pages/Second';
            }
        }
        windowStage.loadContent(url, (err, data) => {
            // ...
        });
    }
}

( 3) The target UIAbility is not launched for the first time

There is often a scenario where when application A has been started and is on the main page, go back to the desktop, open application B, start application A again from application B, and need to jump to the specified page of application A. For example, the scenario where the contact application and the SMS application are used together. Open the homepage of the SMS application and return to the desktop. At this time, the SMS application is in the open state and is currently on the homepage of the SMS application. Then open the homepage of the contacts application, enter the contact user A to view the details, click the SMS icon, and prepare to send a text message to user A. At this time, the SMS application will be launched again and is currently on the sending page of the SMS application.

%E5%9B%BE%E7%89%879.png

For the above scenario, that is, when the UIAbility instance of application A has been created and is in the main page corresponding to the UIAbility instance, at this time, the UIAbility of application A needs to be started again from application B, and it needs to jump to a different page. How to achieve this situation?

1. In the target UIAbility, the Index page is loaded by default. Since the current UIAbility instance has been created before, it will enter the onNewWant() callback of UIAbility at this time and will not enter the onCreate() and onWindowStageCreate() lifecycle callbacks. In the onNewWant() callback, parse the want parameter passed by the caller. And hang it in the global variable globalThis, so that it can be obtained later on the page.

import UIAbility from '@ohos.app.ability.UIAbility'

export default class FuncAbility extends UIAbility {
    onNewWant(want, launchParam) {
        // 接收调用方UIAbility传过来的参数
        globalThis.funcAbilityWant = want;
        // ...
    }
}

2. In FuncAbility, at this time, it is necessary to use the page routing Router module in the Index page to realize the jump of the specified page. Since the Index page corresponding to FuncAbility is active at this time, it will not re-declare variables and enter the aboutToAppear() life cycle. Calling back. Therefore, the function of page routing jump can be realized in the onPageShow() life cycle callback of the Index page.

import router from '@ohos.router';

@Entry
@Component
struct Index {
  onPageShow() {
    let funcAbilityWant = globalThis.funcAbilityWant;
    let url2 = funcAbilityWant?.parameters?.router;
    if (url2 && url2 === 'funcA') {
      router.replaceUrl({
        url: 'pages/Second',
      })
    }
  }

  // 页面展示
  build() {
    // ...
  }
}

Note : When the startup mode of the called Ability is set to the standard startup mode, a new instance will be created every time it starts, so the onNewWant() callback will not be used.

6. Implement UIAbility interaction through Call (only open to system applications)

Call is an extension of UIAbility, which provides UIAbility with the ability to be called and communicate with the outside. Call supports both foreground and background startup methods, so that UIAbility can be pulled to the foreground to display the UI, and can also be created and run in the background. Call calls establish IPC communication between the caller and the called party, so application developers can implement data sharing between different abilities through Call calls.

The core interface called by Call is the startAbilityByCall method, which differs from the startAbility interface in that:

startAbilityByCall supports both foreground and background startup methods, while startAbility only supports foreground startup. The caller can use the Caller object returned by startAbilityByCall to communicate with the callee, but startAbilty does not have the communication capability.

The usage scenarios of Call mainly include:

Needed to communicate with the UIAbility being activated. The UIAbility that is expected to be launched runs in the background.

Table 1  Explanation of terms related to Call

noun

describe

CallerAbility

The UIAbility (the caller) that makes the Call call.

CalleeAbility

The UIAbility (the callee) invoked by Call.

Caller

The actual object, returned by the startAbilityByCall interface, CallerAbility can use Caller to communicate with CalleeAbility.

Callee

The actual object, held by CalleeAbility, can communicate with Caller.

The call diagram is shown below.

Figure 1  Schematic diagram of Call call

%E5%9B%BE%E7%89%8710.png

CallerAbility calls the startAbilityByCall interface to obtain a Caller, and uses the call method of the Caller object to send data to CalleeAbility.

CalleeAbility holds a Callee object, and registers a callback function through the Callee's on method. When the data sent by the Caller is received, the corresponding callback function will be called.

Note : Currently only system apps are supported to use Call calls. The startup mode of CalleeAbility needs to be a single instance. The Call call supports both local (in-device) Call calls and cross-device Call calls. The following introduces the Call call methods within the device.

( 1) Interface description

The main interfaces of the Call function are shown in the table below. For details about the API, see the interface documentation.

Table 2  Call function main interface

interface name

describe

startAbilityByCall(want: Want): Promise<Caller>

Start the specified UIAbility and obtain its Caller communication interface. The default is to start in the background. You can start it in the foreground by configuring want. For details, see the interface document. Both AbilityContext and ServiceExtensionContext support this interface.

on(method: string, callback: CalleeCallBack): void

The general component Callee registers the callback method corresponding to the method.

off(method: string): void

Common component Callee unregisters the callback method of the method.

call(method: string, data: rpc.Parcelable): Promise<void>

Send contracted serialized data to the common component Callee.

callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence>

Send the agreed serialized data to the common component Callee, and bring back the agreed serialized data returned by Callee.

release(): void

Release the Caller communication interface of the common component.

on(type: "release", callback: OnReleaseCallback): void

Register common component communication disconnection listener notification.

Implementing UIAbility interaction through Call calls in the device involves the following two parts of development: Create the called end of the Callee. Access the called end of the Callee.

( 2) Development steps (creating the called end of Callee)

At the called end of Callee, it is necessary to implement the data receiving callback function of the specified method, and the data serialization and deserialization methods. During the period when data needs to be received, the monitor is registered through the on interface, and the monitor is released through the off interface when there is no need to receive data.

1. Configure the startup mode of Ability.

Configure module.json5, and configure CalleeAbility as a single instance "singleton".

JSON field

field description

"launchType"

Ability's startup mode, set to "singleton" type.

An example of the Ability configuration tag is as follows:

"abilities":[{
  "name": ".CalleeAbility",
  "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
  "launchType": "singleton",
  "description": "$string:CalleeAbility_desc",
  "icon": "$media:icon",
  "label": "$string:CalleeAbility_label",
  "visible": true
}]

2. Import the UIAbility module.

import Ability from '@ohos.app.ability.UIAbility';

3. Define the agreed serialized data.

The format of the data sent and received by the calling end and the called end needs to be agreed upon through negotiation. The following example agrees that the data consists of numbers and strings.

export default class MyParcelable {
    num: number = 0
    str: string = ""

    constructor(num, string) {
        this.num = num
        this.str = string
    }

    marshalling(messageSequence) {
        messageSequence.writeInt(this.num)
        messageSequence.writeString(this.str)
        return true
    }

    unmarshalling(messageSequence) {
        this.num = messageSequence.readInt()
        this.str = messageSequence.readString()
        return true
    }
}

4. Realize Callee.on monitoring and Callee.off release monitoring.

The registration timing of the monitoring function of the callee Callee depends on the application developer. The data before registering to monitor will not be processed, and the data after canceling the monitor will not be processed. The following example registers the 'MSG_SEND_METHOD' listener in onCreate of Ability, cancels the listener in onDestroy, performs corresponding processing and returns after receiving the serialized data, and the application developer performs corresponding processing according to actual needs. The specific sample code is as follows:

const TAG: string = '[CalleeAbility]';
const MSG_SEND_METHOD: string = 'CallSendMsg';

function sendMsgCallback(data) {
    console.info('CalleeSortFunc called');

    // 获取Caller发送的序列化数据
    let receivedData = new MyParcelable(0, '');
    data.readParcelable(receivedData);
    console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);

    // 作相应处理
    // 返回序列化数据result给Caller
    return new MyParcelable(receivedData.num + 1, `send ${receivedData.str} succeed`);
}

export default class CalleeAbility extends Ability {
    onCreate(want, launchParam) {
        try {
            this.callee.on(MSG_SEND_METHOD, sendMsgCallback);
        } catch (error) {
            console.info(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
        }
    }

    onDestroy() {
        try {
            this.callee.off(MSG_SEND_METHOD);
        } catch (error) {
            console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`);
        }
    }
}copy copy

(3) Development steps (access to the called end of Callee)

1. Import the UIAbility module.

import Ability from '@ohos.app.ability.UIAbility';

2. Obtain the Caller communication interface.

The context attribute of Ability implements the startAbilityByCall method, which is used to obtain the Caller communication interface of the specified common component. The following example obtains the context attribute of the Ability instance through this.context, uses startAbilityByCall to pull up the called end of the Callee and obtain the Communication Interface of the Caller, and registers the onRelease listener of the Caller. The application developer should deal with it according to actual needs.

// 注册caller的release监听
private regOnRelease(caller) {
    try {
        caller.on("release", (msg) => {
            console.info(`caller onRelease is called ${msg}`);
        })
        console.info('caller register OnRelease succeed');
    } catch (error) {
        console.info(`caller register OnRelease failed with ${error}`);
    }
}

async onButtonGetCaller() {
    try {
        this.caller = await context.startAbilityByCall({
            bundleName: 'com.samples.CallApplication',
            abilityName: 'CalleeAbility'
        })
        if (this.caller === undefined) {
            console.info('get caller failed')
            return
        }
        console.info('get caller success')
        this.regOnRelease(this.caller)
    } catch (error) {
        console.info(`get caller failed with ${error}`)
    }
}

Guess you like

Origin blog.csdn.net/weixin_69135651/article/details/131848054