使用AppServiceExtensionAbility组件实现后台服务

概述

从API version 20开始,支持开发者使用AppServiceExtensionAbility组件,为应用提供后台服务能力,其他三方应用可通过启动或连接该AppServiceExtensionAbility组件获取相应的服务。 例如,企业部署的数据防泄漏 (DLP) 软件需要能够长期无界面运行,持续监听文件操作、网络流量,并拦截违规行为,可以使用AppServiceExtensionAbility组件来实现其核心的后台监控服务。

说明

本文将被启动或被连接的AppServiceExtensionAbility组件称为服务端,将启动或连接AppServiceExtensionAbility组件的应用组件(当前仅支持UIAbility)称为客户端。

约束与限制

设备限制

AppServiceExtensionAbility组件当前仅支持2in1设备。

规格限制

  • 应用集成AppServiceExtensionAbility组件需要申请ACL权限(ohos.permission.SUPPORT_APP_SERVICE_EXTENSION)。该ACL权限当前只对企业普通应用开放申请。

  • AppServiceExtensionAbility组件内不支持调用window相关API。

运作机制

开发者可以在UIAbility中以启动连接的方式来拉起AppServiceExtensionAbility组件。

下表展示了拉起和连接的几种场景:

说明

“客户端是否可信”为是时,表示客户端属于服务端所属应用或已配置在appIdentifierAllowList中。为否时,表示客户端不属于服务端所属应用且未配置在appIdentifierAllowList中。

客户端操作 服务端状态 客户端是否可信 结果说明
startAppServiceExtensionAbility 未启动 成功,服务端通过start方式启动,服务端状态变为已启动。
startAppServiceExtensionAbility 未启动 失败,客户端不在允许列表中,无法调用启动服务。
startAppServiceExtensionAbility 已启动 成功,服务端已经启动,start操作直接返回成功。
startAppServiceExtensionAbility 已启动 失败,客户端不在允许列表中,无法调用启动服务。
connectAppServiceExtensionAbility 未启动 成功,服务端通过connect方式启动,并建立连接。
connectAppServiceExtensionAbility 未启动 失败,客户端不在允许列表中,无法启动服务端。
connectAppServiceExtensionAbility 已启动 成功,服务端已启动,直接建立连接。
connectAppServiceExtensionAbility 已启动 成功,服务端已启动,直接建立连接。

实现一个后台服务

在DevEco Studio工程中手动新建一个AppServiceExtensionAbility组件,具体步骤如下:

  1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为myappserviceextability。

  2. 在myappserviceextability目录,右键选择“New > ArkTS File”,新建一个文件并命名为MyAppServiceExtAbility.ets。

    其目录结构如下所示:

    ├── ets
    │ ├── myappserviceextability
    │ │   ├── MyAppServiceExtAbility.ets
    └
    
  3. 在MyAppServiceExtAbility.ets文件中,增加导入AppServiceExtensionAbility的依赖包,自定义类继承AppServiceExtensionAbility组件并实现生命周期回调。

    import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
    import { rpc } from '@kit.IPCKit';
    // ···
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const TAG: string = '[MyAppServiceExtAbility]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    class StubTest extends rpc.RemoteObject {
      constructor(des: string) {
        super(des);
      }
    
      onRemoteMessageRequest(code: number,
        data: rpc.MessageSequence,
        reply: rpc.MessageSequence,
        options: rpc.MessageOption): boolean | Promise<boolean> {
        // 处理客户端发送的消息
        return true;
      }
    }
    
    export default class MyAppServiceExtAbility extends AppServiceExtensionAbility {
      onCreate(want: Want): void {
        let appServiceExtensionContext = this.context;
        hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`);
        // ···
      }
    
      onRequest(want: Want, startId: number): void {
        hilog.info(DOMAIN_NUMBER, TAG, `onRequest, want: ${want.abilityName}`);
      }
    
      onConnect(want: Want): rpc.RemoteObject {
        hilog.info(DOMAIN_NUMBER, TAG, `onConnect, want: ${want.abilityName}`);
        return new StubTest('test');
      }
    
      onDisconnect(want: Want): void {
        hilog.info(DOMAIN_NUMBER, TAG, `onDisconnect, want: ${want.abilityName}`);
      }
    
      onDestroy(): void {
        hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');
      }
    };
    
  4. 在工程Module对应的module.json5配置文件中注册AppServiceExtensionAbility组件,type标签需要设置为“appService”,srcEntry标签表示当前ExtensionAbility组件所对应的代码路径。

    {
      "module": {
        // ···
        "extensionAbilities": [
        // ···
          {
            "name": "MyAppServiceExtAbility",
            "description": "appService",
            "type": "appService",
            "exported": true,
            "srcEntry": "./ets/myappserviceextability/MyAppServiceExtAbility.ets",
            "appIdentifierAllowList": [
              // 此处填写允许启动该后台服务的客户端应用的appIdentifier列表
            ],
          }
        ]
      }
    }
    

启动一个后台服务

应用通过startAppServiceExtensionAbility()方法启动一个后台服务,服务的onRequest()回调就会被调用,并在该回调方法中接收到调用者传递过来的Want对象。后台服务启动后,其生命周期独立于客户端,即使客户端已经销毁,该后台服务仍可继续运行。因此,后台服务需要在其工作完成时通过调用AppServiceExtensionContextterminateSelf()来自行停止,或者由另一个组件调用stopAppServiceExtensionAbility()来将其停止。

说明:

AppServiceExtensionAbility组件以start方式启动,并且没有连接的时候,AppServiceExtensionAbility组件进程可能被挂起(请参考Background Tasks Kit简介)。

  • 在应用中启动一个新的AppServiceExtensionAbility组件。示例中的context的获取方式请参见获取UIAbility的上下文信息

    import { common, Want } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    const TAG: string = '[StartAppServiceExt]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct StartAppServiceExt {
      build() {
        Column() {
        // ···
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                // ···
              }
            // ···
              .onClick(() => {
                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
                let want: Want = {
                  deviceId: '',
                  bundleName: 'com.samples.appserviceextensionability',
                  abilityName: 'MyAppServiceExtAbility'
                };
                context.startAppServiceExtensionAbility(want).then(() => {
                  hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting AppServiceExtensionAbility.');
                  // 成功启动后台服务
                  this.getUIContext().getPromptAction().showToast({
                    message: 'SuccessfullyStartBackendService'
                  });
                }).catch((err: BusinessError) => {
                  hilog.error(DOMAIN_NUMBER, TAG,
                    `Failed to start AppServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
                });
              })
            }
    
            // ···
          }
        // ···
        }
    
        // ···
      }
    }
    
  • 在应用中停止一个已启动的AppServiceExtensionAbility组件。

    import { common, Want } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    const TAG: string = '[StopAppServiceExt]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Entry
    @Component
    struct StopAppServiceExt {
      build() {
        Column() {
        // ···
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                // ···
              }
            // ···
              .onClick(() => {
                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
                let want: Want = {
                  deviceId: '',
                  bundleName: 'com.samples.appserviceextensionability',
                  abilityName: 'MyAppServiceExtAbility'
                };
                context.stopAppServiceExtensionAbility(want).then(() => {
                  hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in stopping AppServiceExtensionAbility.');
                  this.getUIContext().getPromptAction().showToast({
                    message: 'SuccessfullyStoppedAStartedBackendService'
                  });
                }).catch((err: BusinessError) => {
                  hilog.error(DOMAIN_NUMBER, TAG,
                    `Failed to stop AppServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
                });
              })
            }
    
            // ···
          }
    
        // ···
        }
    
        // ···
      }
    }
    
  • 已启动的AppServiceExtensionAbility组件停止自身。

    import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
    // ···
    import { BusinessError } from '@kit.BasicServicesKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const TAG: string = '[MyAppServiceExtAbility]';
    // ···
    
    export default class MyAppServiceExtAbility extends AppServiceExtensionAbility {
      onCreate(want: Want): void {
        // ···
        // 执行业务逻辑
        this.context.terminateSelf().then(() => {
          hilog.info(0x0000, TAG, '----------- terminateSelf succeed -----------');
        }).catch((error: BusinessError) => {
          hilog.error(0x0000, TAG, `terminateSelf failed, error.code: ${error.code}, error.message: $   {error.message}`);
        });
      }
    
    // ···
    };
    

连接一个后台服务

客户端连接服务端

客户端可以通过connectAppServiceExtensionAbility()连接服务端(在Want对象中指定连接的目标服务),服务端的onConnect()就会被调用,并在该回调方法中接收到客户端传递过来的Want对象。

服务端的AppServiceExtensionAbility组件会在onConnect()中返回IRemoteObject对象给客户端ConnectOptionsonConnect()方法。开发者通过该IRemoteObject定义通信接口,实现客户端与服务端的RPC交互。多个客户端可以同时连接到同一个后台服务,客户端完成与服务端的交互后,客户端需要通过调用disconnectAppServiceExtensionAbility()来断开连接。如果所有连接到某个后台服务的客户端均已断开连接,则系统会销毁该服务。

  • 使用connectAppServiceExtensionAbility()建立与后台服务的连接。示例中的context的获取方式请参见获取UIAbility的上下文信息

    import { common, Want } from '@kit.AbilityKit';
    import { rpc } from '@kit.IPCKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const TAG: string = '[ConnectAppServiceExt]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    let connectionId: number;
    let want: Want = {
      deviceId: '',
      bundleName: 'com.samples.appserviceextensionability',
      abilityName: 'MyAppServiceExtAbility'
    };
    
    let options: common.ConnectOptions = {
      onConnect(elementName, remote: rpc.IRemoteObject): void {
        hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
        if (remote === null) {
          hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
          return;
        }
        // 通过remote进行通信
      },
      onDisconnect(elementName): void {
        hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
      },
      onFailed(code: number): void {
        hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code));
      }
    };
    
    @Entry
    @Component
    struct ConnectAppServiceExt {
      build() {
        Column() {
        // ···
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                // ···
              }
            // ···
              .onClick(() => {
                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
                // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
                connectionId = context.connectAppServiceExtensionAbility(want, options);
                // 成功连接后台服务
                this.getUIContext().getPromptAction().showToast({
                  message: 'SuccessfullyConnectBackendService'
                });
                hilog.info(DOMAIN_NUMBER, TAG, `connectionId is : ${connectionId}`);
              })
            }
    
            // ···
          }
    
        // ···
        }
    
        // ···
      }
    }
    
  • 使用disconnectAppServiceExtensionAbility()断开与后台服务的连接。

    import { common } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    const TAG: string = '[DisConnectAppServiceExt]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    let connectionId: number;
    
    @Entry
    @Component
    struct DisConnectAppServiceExt {
      build() {
        Column() {
        // ···
          List({ initialIndex: 0 }) {
            ListItem() {
              Row() {
                // ···
              }
            // ···
              .onClick(() => {
                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
                // connectionId为调用connectServiceExtensionAbility接口时的返回值,需开发者自行维护
                context.disconnectAppServiceExtensionAbility(connectionId).then(() => {
                  hilog.info(DOMAIN_NUMBER, TAG, 'disconnectAppServiceExtensionAbility success');
                  // 成功断连后台服务
                  this.getUIContext().getPromptAction().showToast({
                    message: 'SuccessfullyDisconnectBackendService'
                  });
                }).catch((error: BusinessError) => {
                  hilog.error(DOMAIN_NUMBER, TAG, 'disconnectAppServiceExtensionAbility failed');
                });
              })
            }
    
            // ···
          }
    
        // ···
        }
    
        // ···
      }
    }
    

客户端与服务端通信

客户端在onConnect()中获取到rpc.IRemoteObject对象后便可与服务端进行通信。

客户端:使用sendMessageRequest接口向服务端发送消息。

import { common, Want } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = '[ClientServerExt]';
const DOMAIN_NUMBER: number = 0xFF00;
const REQUEST_CODE = 1;
let connectionId: number;
let want: Want = {
  deviceId: '',
  bundleName: 'com.samples.appserviceextensionability',
  abilityName: 'MyAppServiceExtAbility'
};
let options: common.ConnectOptions = {
  onConnect(elementName, remote): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
    if (remote === null) {
      hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
      return;
    }
    let option = new rpc.MessageOption();
    let data = new rpc.MessageSequence();
    let reply = new rpc.MessageSequence();

    // 写入请求数据
    data.writeInt(1);
    data.writeInt(2);

    remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
      if (ret.errCode === 0) {
        hilog.info(DOMAIN_NUMBER, TAG, `sendRequest got result`);
        let sum = ret.reply.readInt();
        hilog.info(DOMAIN_NUMBER, TAG, `sendRequest success, sum:${sum}`);
      } else {
        hilog.error(DOMAIN_NUMBER, TAG, `sendRequest failed`);
      }
    }).catch((error: BusinessError) => {
      hilog.error(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`);
    });
  },
  onDisconnect(elementName): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
  },
  onFailed(code): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback');
  }
};

// 调用connectAppServiceExtensionAbility相关代码

@Entry
@Component
struct ClientServerExt {
  build() {
    Column() {
    // ···
      List({ initialIndex: 0 }) {
        ListItem() {
          Row() {
            // ···
          }
        // ···
          .onClick(() => {
            let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
            connectionId = context.connectAppServiceExtensionAbility(want, options);
            hilog.info(DOMAIN_NUMBER, TAG, `connectionId is : ${connectionId}`);
          })
        }
      }
    // ···
    }
  }
}

服务端:使用onRemoteMessageRequest接口接收客户端发送的消息。

import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = '[MyAppServiceExtAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

// 开发者需要在这个类型里对接口进行实现
class Stub extends rpc.RemoteObject {
  onRemoteMessageRequest(code: number,
    data: rpc.MessageSequence,
    reply: rpc.MessageSequence,
    options: rpc.MessageOption): boolean | Promise<boolean> {
    hilog.info(DOMAIN_NUMBER, TAG, 'onRemoteMessageRequest');
    let sum = data.readInt() + data.readInt();
    reply.writeInt(sum);
    return true;
  }
}

// 服务端实现
export default class MyAppServiceExtAbility extends AppServiceExtensionAbility {
  onCreate(want: Want): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'MyAppServiceExtAbility onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'MyAppServiceExtAbility onDestroy');
  }

  onConnect(want: Want): rpc.RemoteObject {
    hilog.info(DOMAIN_NUMBER, TAG, 'MyAppServiceExtAbility onConnect');
    return new Stub('test');
  }

  onDisconnect(): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'MyAppServiceExtAbility onDisconnect');
  }
}

服务端对客户端身份校验

部分开发者需要使用AppServiceExtensionAbility组件提供一些较为敏感的服务,可以通过如下方式对客户端身份进行校验。

通过callerUid识别客户端应用

通过调用getCallingUid()接口获取客户端的uid,再调用getBundleNameByUid()接口获取uid对应的bundleName,从而识别客户端身份。此处需要注意的是getBundleNameByUid()是一个异步接口,因此服务端无法将校验结果返回给客户端,这种校验方式适合客户端向服务端发起执行异步任务请求的场景,示例代码如下:

import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
import { bundleManager } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import { osAccount, BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = '[MyAppServiceExtAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

class Stub extends rpc.RemoteObject {
  private validAppIdentifier: string = 'your_valid_app_identifier_here';

  onRemoteMessageRequest(
    code: number,
    data: rpc.MessageSequence,
    reply: rpc.MessageSequence,
    options: rpc.MessageOption): boolean | Promise<boolean> {
    this.verifyClientIdentity().then((isValid: boolean) => {
      if (isValid) {
        hilog.info(DOMAIN_NUMBER, TAG, 'Client authentication PASSED');
      } else {
        hilog.error(DOMAIN_NUMBER, TAG, 'Client authentication FAILED');
      }
    }).catch((err: BusinessError) => {
      hilog.error(DOMAIN_NUMBER, TAG, `Authentication error: ${err.code}, ${err.message}`);
    });
    return true;
  }

  private async verifyClientIdentity(): Promise<boolean> {
    try {
      const callerUid: number = rpc.IPCSkeleton.getCallingUid();
      hilog.info(DOMAIN_NUMBER, TAG, `Caller UID: ${callerUid}`);

      const userId: number = await this.getUserIdByUid(callerUid);
      hilog.info(DOMAIN_NUMBER, TAG, `User ID: ${userId}`);

      const bundleName: string = await bundleManager.getBundleNameByUid(callerUid);
      hilog.info(DOMAIN_NUMBER, TAG, `Bundle Name: ${bundleName}`);

      const bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO;
      const bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfo(bundleName, bundleFlags, userId);

      if (bundleInfo.signatureInfo && bundleInfo.signatureInfo.appIdentifier) {
        const appIdentifier: string = bundleInfo.signatureInfo.appIdentifier;
        hilog.info(DOMAIN_NUMBER, TAG, `App Identifier: ${appIdentifier}`);
        return appIdentifier === this.validAppIdentifier;
      }
      return false;
    } catch (err) {
      if (err instanceof Error) {
        hilog.error(DOMAIN_NUMBER, TAG, `Verification failed: ${err.message}`);
      } else {
        hilog.error(DOMAIN_NUMBER, TAG, `Verification failed: ${String(err)}`);
      }
      return false;
    }
  }

  private async getUserIdByUid(uid: number): Promise<number> {
    try {
      const accountManager = osAccount.getAccountManager();
      const userId: number = await accountManager.getOsAccountLocalIdForUid(uid);
      return userId;
    } catch (err) {
      if (err instanceof Error) {
        hilog.error(DOMAIN_NUMBER, TAG, `Get userId failed: ${err.message}`);
        throw err;
      } else {
        const error = new Error(String(err));
        hilog.error(DOMAIN_NUMBER, TAG, `Get userId failed: ${error.message}`);
        throw error;
      }
    }
  }
}

export default class MyAppServiceExtAbility extends AppServiceExtensionAbility {
  onConnect(want: Want): rpc.RemoteObject {
    return new Stub('test');
  }
  // 其他生命周期
}

通过callerTokenId对客户端进行鉴权

通过调用getCallingTokenId()接口获取客户端的tokenID,再调用verifyAccessTokenSync()接口判断客户端是否有某个具体权限,由于当前不支持自定义权限,因此只能校验当前系统所定义的权限。示例代码如下:

import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = '[AppServiceExtImpl]';
const DOMAIN_NUMBER: number = 0xFF00;

// 开发者需要在这个类里进行实现

class Stub extends rpc.RemoteObject {
  onRemoteMessageRequest(
    code: number,
    data: rpc.MessageSequence,
    reply: rpc.MessageSequence,
    options: rpc.MessageOption): boolean | Promise<boolean> {
    // 开发者自行实现业务逻辑
    hilog.info(DOMAIN_NUMBER, TAG, `onRemoteMessageRequest: ${data}`);
    let callerUid = rpc.IPCSkeleton.getCallingUid();
    bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
      hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
      // 对客户端包名进行识别
      if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // 识别不通过
        hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
        return;
      }
      // 识别通过,执行正常业务逻辑
    }).catch((err: BusinessError) => {
      hilog.error(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
    });

    let callerTokenId = rpc.IPCSkeleton.getCallingTokenId();
    let accessManager = abilityAccessCtrl.createAtManager();
    // 所校验的具体权限由开发者自行选择,此处ohos.permission.GET_BUNDLE_INFO_PRIVILEGED只作为示例
    let grantStatus = accessManager.verifyAccessTokenSync(callerTokenId, 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED');
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
      hilog.error(DOMAIN_NUMBER, TAG, 'PERMISSION_DENIED');
      return false;
    }
    hilog.info(DOMAIN_NUMBER, TAG, 'verify access token success.');
    return true;
  }
}

export default class MyAppServiceExtAbility extends AppServiceExtensionAbility {
  onConnect(want: Want): rpc.RemoteObject {
    return new Stub('test');
  }
  // 其他生命周期
}