# 代理方法
小程序中部分业务是抽象定义的,这些抽象的业务通过接口的形式暴露给了外部,外部可以自行实现具体的业务逻辑。
函数签名如果是需要返回 boolean 类型表示是否需要阻止默认行为,如果需要阻止就返回
true
,否则则返回false
函数里的参数
appId
和apiServer
均为触发的小程序的信息,可以根据这两个数据来对不同的小程序来执行不同的逻辑
# 1. CapsuleHandler
胶囊按钮的代理类
// namespace IFinProxyHandlerItem class CapsuleHandler { /** * 点击关闭按钮时触发 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns 返回 true 表示宿主自行处理,返回 false 表示宿主处理完,仍执行后续的默认操作 */ public onCloseButtonClick(appId: string, apiServer: string): boolean /** * 点击更多按钮时触发 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns 返回 true 表示宿主自行处理,返回 false 表示宿主处理完,仍执行后续的默认操作 */ public onMoreButtonClick(appId: string, apiServer: string): boolean }
已复制代码
示例代码:
import { FinAppProxyHandlerManager, IFinProxyHandlerItem } from '@finclip/sdk' import { promptAction } from '@kit.ArkUI' class CapsuleHandler extends IFinProxyHandlerItem.CapsuleHandler { onCloseButtonClick(appId: string, apiServer: string): boolean { this.promptMsg(`${appId},关闭按钮点击了`) return false } onMoreButtonClick(appId: string, apiServer: string): boolean { this.promptMsg(`${appId},更多按钮点击了`) return false } private promptMsg(message: string) { promptAction.showToast({ message }) } } FinAppProxyHandlerManager.capsuleHandler = new CapsuleHandler()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class CapsuleHandler { // 更多按钮的点击事件 onMoreButtonClick?: (appId: string, apiServer: string) => boolean // 关闭按钮的点击事件 onCloseButtonClick?: (appId: string, apiServer: string) => boolean }
已复制代码
示例代码
client.proxyHandlerManager.capsuleHandler.onMoreButtonClick = (appId: string, apiServer: string) => { // do something return false // 不阻止默认行为 }
已复制代码
# 2. MoreMenuHandler
更多菜单的代理类
// namespace IFinProxyHandlerItem class MoreMenuHandler { /** * 当收到小程序返回的数据时触发 * @param contentInfo 小程序返回的信息 * @returns */ public onCustomMenuItemClickWithInfo(appId: string, apiServer: string, contentInfo: IFinAppProxy.IMoreMenuItemContentInfo) /** * 当更多按钮菜单点击时出发 * @param type 菜单按钮的唯一标识 * @param currentPath 小程序当前的页面路径 * @returns */ public onMoreMenuItemClick(appId: string, apiServer: string, type: string, currentPath: string): boolean | void /** * 获取更多菜单的按钮列表 * @returns 更多菜单的按钮列表 */ public getMoreMenuItems(): IFinAppProxy.IMoreMenuItem[] }
已复制代码
示例代码:
import { FinAppProxyHandlerManager, IFinAppProxy, IFinProxyHandlerItem } from '@finclip/sdk' import { promptAction } from '@kit.ArkUI' class MoreMenuHandler extends IFinProxyHandlerItem.MoreMenuHandler { onCustomMenuItemClickWithInfo(appId: string, apiServer: string, contentInfo: IFinAppProxy.IMoreMenuItemContentInfo) { this.promptMsg(`小程序 ${apiServer} ${appId} 的 ${contentInfo.path} 页面的菜单 ${contentInfo.menuId} 被点击了,返回的数据为${JSON.stringify(contentInfo.params)}`) } onMoreMenuItemClick(appId: string, apiServer: string, menuItemId: string, currentPath: string): boolean | void { this.promptMsg(`小程序 ${apiServer} ${appId} 的 ${currentPath} 页面的菜单 ${menuItemId} 被点击了`) } getMoreMenuItems(): IFinAppProxy.IMoreMenuItem[] { return [ { label: '自定义', icon: $r('app.media.app_icon'), menuItemId: 'custom', menuType: 'onMiniProgram' } ] } private promptMsg(message: string) { promptAction.showToast({ message }) } } FinAppProxyHandlerManager.moreMenuHandler = new MoreMenuHandler()
已复制代码
// 小程序端 Page({ onCustomButtonHandler(){ return { appInfo:'this is appInfo' } } })
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class MoreMenuHandler { /** * @param type 菜单按钮的唯一标识 * @param currentPath 小程序当前的页面路径 * @returns * */ onMoreMenuItemClick?: (appId: string, apiServer: string, type: string, currentPath: string) => void /** * 当 onMiniProgram 类型的按钮点击时出发,携带小程序返回的信息 * @param contentInfo 小程序返回的信息 * @returns */ onCustomMenuItemClickWithInfo?: (appId: string, apiServer: string, contentInfo: IFinAppProxy.IMoreMenuItemContentInfo) => void /** * @returns 自定义更多菜单的按钮 */ getMoreMenuItems: () => IMoreMenuItem[] }
已复制代码
示例代码
client.proxyHandlerManager.moreMenuHandler.onMoreMenuItemClick = (appId: string, apiServer: string, type: string, currentPath: string) => { // do something } client.proxyHandlerManager.moreMenuHandler.onCustomMenuItemClickWithInfo = (appId: string, apiServer: string, contentInfo: IFinAppProxy.IMoreMenuItemContentInfo) => { if(contentInfo.menuId === 'custom'){ // do something } } client.proxyHandlerManager.moreMenuHandler.getMoreMenuItems = () => { return [ { label: '自定义 Btn', icon: $r('app.media.app_icon'), menuItemId: 'custom' } ] }
已复制代码
IMoreMenuItem
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
label | String | 是 | 小程序 id |
icon | ResourceStr | 是 | 菜单按钮的图片资源 |
disableIcon | ResourceStr | 否 | 菜单按钮禁用的图片资源 |
darkIcon | ResourceStr | 否 | 暗黑模式菜单按钮的图片资源 |
disableDarkIcon | ResourceStr | 否 | 暗黑模式菜单按钮禁用的图片资源 |
menuItemId | String | 是 | 菜单按钮的唯一标识,即 onMoreMenuItemClick 参数的 type |
hover | Boolean | 否 | 是否开启 hover 效果 |
disable | Boolean | 否 | 是否禁用 |
IMoreMenuItemContentInfo
属性 | 类型 | 描述 |
---|---|---|
title | String | 小程序名称 |
logo | String | 小程序 logo |
description | String | 小程序描述 |
path | String | 当前页面路径 |
menuId | String | 菜单按钮的唯一标识 |
params | IMoreMenuItemParams | 由小程序返回的原始数据 |
IMoreMenuItemParams
属性 | 类型 |
---|---|
title | String |
desc | String |
path | String |
appInfo | object |
# 3. PrivacyHandler
隐私协议的代理类
// namespace IFinProxyHandlerItem export class PrivacyHandler { /** * @param scope 当前请求的权限,如果为空则是在关于页面显示的隐私协议 * @returns IFinApplet.IPrivacy */ public getPrivacyInfo(appId: string, apiServer: string, scope?: string): IFinApplet.IPrivacy | void }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinApplet, IFinProxyHandlerItem } from '@finclip/sdk' class PrivacyHandler extends IFinProxyHandlerItem.PrivacyHandler { getPrivacyInfo(appId: string, apiServer: string, scope?: string): IFinApplet.IPrivacy | void { return { title: '自定义授权弹窗标题', docName: '自定义隐私协议文档名称', docUrl: 'https://www.finclip.com', copyWriting: '自定义授权弹窗文案,隐私协议文档名称为《自定义隐私协议文档名称》' } } } FinAppProxyHandlerManager.privacyHandler = new PrivacyHandler()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class PrivacyHandler { /** * @param scope 当前请求的权限,如果为空则是在关于页面显示的隐私协议 * @returns IFinApplet.IPrivacy */ getPrivacyInfo?: (appId: string, apiServer: string, scope?: string) => IFinApplet.IPrivacy }
已复制代码
示例代码
client.proxyHandlerManager.privacyHandler.getPrivacyInfo = (appId: string, apiServer: string, scope?: string) => { return { title: '自定义授权弹窗标题', docName: '自定义隐私协议文档名称', docUrl: 'https://www.finclip.com', copyWriting: '自定义授权弹窗文案,隐私协议文档名称为《自定义隐私协议文档名称》' } }
已复制代码
IFinApplet.IPrivacy
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
title | String | 是 | 自定义隐私授权弹窗标题 |
copyWriting | String | 是 | 自定义隐私授权弹窗文案,内容包含 自定义隐私协议文档名称 |
docName | String | 是 | 自定义隐私协议文档名称 |
docUrl | String | 是 | 自定义隐私协议文档链接 |
# 4. ScopeHandler
自定义权限的代理类
// namespace IFinProxyHandlerItem export class ScopeHandler { /** * 是否自定义小程序权限设置页 */ public isAppletCustomizeSettingPage: boolean = false /** * 自定义小程序权限设置页 * @param applet * @param scopes * @param updateScopes 更新 scopes 的方法 * @returns boolean 是否实现了代理,如果返回 false 表示未实现代理,会走默认的逻辑 */ public openSettingPage(applet: IFinApplet.IAppletInfo, scopes: IFinApplet.IScope[], updateScopes: (result: IFinAppProxy.ISettingListParams) => void): boolean /** * 注册自定义权限 * @param appId * @param apiServer * @returns 自定义权限列表 */ public getCustomScopes(appId: string, apiServer: string): IFinApplet.IScope[] /** * 自定义弹窗,实现方式可以参考示例代码 * @returns 弹窗 builder */ public getCustomView(): (() => void) | void /** * @param api 当初小程序触发的 API 名称 * @param context 当前 Ability 的 context * @param scopes 权限列表,包括内置权限和自定义权限 * @param callback API 的回调函数,如果用户通过权限调用 callback 传 true,后续则会走自定义 API 的逻辑,否则则直接走 fail 逻辑 * @returns boolean 是否实现了代理,如果返回 false 表示未实现代理,会走默认的权限逻辑 */ public onCustomApiInvoke(appId: string, apiServer: string, api: string, context: common.UIAbilityContext, scopes: IFinApplet.IScope[], callback: (res: boolean) => void): boolean }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinApplet, IFinAppProxy, IFinProxyHandlerItem } from '@finclip/sdk' import { promptAction } from '@kit.ArkUI' import { ISettingRouterParams } from '../../pages/Setting' import { getFinAppClient } from '../FinAppClient' import { common } from '@kit.AbilityKit' class ScopeHandler extends IFinProxyHandlerItem.ScopeHandler { isAppletCustomizeSettingPage = true openSettingPage(applet: IFinApplet.IAppletInfo, scopes: IFinApplet.IScope[], updateScopes: (result: IFinAppProxy.ISettingListParams) => void): boolean { const param: ISettingRouterParams = { applet, scopes } // 以 Navigation 的方式初始化,使用 Navigation 跳转授权管理页 getFinAppClient().getEntryInfo().routerState?.pushPath({ name: 'Setting', param, onPop: (info) => { const param = info.result as ISettingRouterParams updateScopes({ scopes: param.scopes, applet: param.applet }) } }) return true } getCustomScopes(appId: string, apiServer: string): IFinApplet.IScope[] { return [ { scope: 'idCard', scopeName: '身份证', title: '获取身份证信息', desc: "获取您的身份证信息用于XXXXXX", scopeStatus: 0 } ] } getCustomView(): (() => void) | void { return customView } onCustomApiInvoke(appId: string, apiServer: string, api: string, context: common.UIAbilityContext, scopes: IFinApplet.IScope[], callback: (res: boolean) => void): boolean { const scope = scopes.find(i => i.scope === 'idCard') if (scope?.scopeStatus === 0) { context.eventHub.emit('showCustomToast', api) context.eventHub.on('onShowCustomToast', (res: boolean) => { scope.scopeStatus = res ? 3 : 1 callback(res) context.eventHub.off('onShowCustomToast') }) } else { callback(true) } return true } private promptMsg(message: string) { promptAction.showToast({ message }) } } @Builder function customView() { CustomViewComponent() } @Component struct CustomViewComponent { @State show: boolean = false private context = getContext(this) as common.UIAbilityContext aboutToAppear() { this.context.eventHub.on('showCustomToast', () => { this.show = true }) } handlePermission(res: boolean) { this.context.eventHub.emit('onShowCustomToast', res) this.show = false } @Builder toast() { Stack({ alignContent: Alignment.Bottom }) { Row() { } .height('100%') .width('100%') .backgroundColor('rgba(0,0,0,0.5)') Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) { Row() { Button('拒绝').onClick(() => { this.handlePermission(false) }) Button('同意').onClick(() => { this.handlePermission(true) }) } .width('100%') } .padding({ top: 24, left: 18, right: 18, bottom: 24 }) .width('100%') .height(241) .backgroundColor('#F5F6F6') .clip(true) .borderRadius({ topLeft: 16, topRight: 16 }) .zIndex(10) } } build() { if (this.show) { this.toast() } } } FinAppProxyHandlerManager.scopeHandler = new ScopeHandler()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class ScopeHandler { /** * @param api 当初小程序触发的 API 名称 * @param context 当前 Ability 的 context * @param scopes 权限列表,包括内置权限和自定义权限 * @param callback API 的回调函数,如果用户通过权限调用 callback 传 true,后续则会走自定义 API 的逻辑,否则则直接走 fail 逻辑 * @returns */ onCustomApiInvoke?: (appId: string, apiServer: string, api: string, context: common.UIAbilityContext, scopes: IFinApplet.IScope[], callback: (res: boolean) => void) => void // 自定义弹窗,实现方式可以参考示例代码 getCustomView?: () => (() => void) | void // 注册自定义权限 getCustomScopes: (appId: string, apiServer: string) => IFinApplet.IScope[] // 是否自定义小程序权限设置页 isAppletCustomizeSettingPage?: boolean // 自定义小程序权限设置页 openSettingPage?: (applet: IFinApplet.IAppletInfo, scopes: IFinApplet.IScope[], updateScopes: (result: IFinAppProxy.ISettingListParams) => void) => void }
已复制代码
示例代码
client.proxyHandlerManager.privacyHandler.getPrivacyInfo = (appId: string, apiServer: string, scope?: string) => { return { title: '自定义授权弹窗标题', docName: '自定义隐私协议文档名称', docUrl: 'https://www.finclip.com', copyWriting: '自定义授权弹窗文案,隐私协议文档名称为《自定义隐私协议文档名称》' } }
已复制代码
示例代码
4.1 自定义权限
client.proxyHandlerManager.scopeHandler.getCustomScopes = (appId: string, apiServer: string) => { return [ { scope: 'idCard', scopeName: '身份证', title: '获取身份证信息', desc: "获取您的身份证信息用于XXXXXX", scopeStatus: 0 } ] } @Builder function customView() { CustomViewComponent() } @Component struct CustomViewComponent { @State show: boolean = false private context = getContext(this) as common.UIAbilityContext aboutToAppear() { this.context.eventHub.on('showCustomToast', () => { this.show = true }) } handlePermission(res: boolean) { this.context.eventHub.emit('onShowCustomToast', res) this.show = false } @Builder toast() { Stack({ alignContent: Alignment.Bottom }) { Row() { } .height('100%') .width('100%') .backgroundColor('rgba(0,0,0,0.5)') Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) { Row() { Button('拒绝').onClick(() => { this.handlePermission(false) }) Button('同意').onClick(() => { this.handlePermission(true) }) } .width('100%') } .padding({ top: 24, left: 18, right: 18, bottom: 24 }) .width('100%') .height(241) .backgroundColor('#F5F6F6') .clip(true) .borderRadius({ topLeft: 16, topRight: 16 }) .zIndex(10) } } build() { if (this.show) { this.toast() } }} client.proxyHandlerManager.scopeHandler.getCustomView = () => customView const onCustomApiInvoke = (appId: string, apiServer: string, api: String, context: common.UIAbilityContext, scopes: IFinApplet.IScope[], callback: (res: boolean) => void) => { const scope = scopes.find(i => i.scope === 'idCard') if (scope?.scopeStatus === 0) { context.eventHub.emit('showCustomToast', api) context.eventHub.on('onShowCustomToast', (res: boolean) => { scope.scopeStatus = res ? 3 : 1 callback(res) context.eventHub.off('onShowCustomToast') }) } else { callback(true) } } client.proxyHandlerManager.scopeHandler.onCustomApiInvoke = onCustomApiInvoke
已复制代码
4.2 自定义小程序权限设置页
interface ISettingRouterParams { applet: IFinApplet.IAppletInfo, scopes: IFinApplet.IScope[] } client.proxyHandlerManager.scopeHandler.isAppletCustomizeSettingPage = true client.proxyHandlerManager.scopeHandler.openSettingPage = (applet: IFinApplet.IAppletInfo, scopes: IFinApplet.IScope[], updateScopes) => { const param: ISettingRouterParams = { applet, scopes } client.getEntryInfo().routerState?.pushPath({ name: 'Setting', param, onPop: (info) => { const param = info.result as ISettingRouterParams // 更新权限 updateScopes({ scopes: param.scopes, applet: param.applet }) } }) }
已复制代码
IFinApplet.IScope
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
scope | String | 是 | 权限标识位 |
title | String | 是 | 权限标题 |
desc | String | 是 | 权限描述 |
scopeStatus | EPermissionState | 是 | 权限状态 |
scopeName | String | 是 | 设置页描述 |
EPermissionState
属性 | 值 | 描述 |
---|---|---|
UNSET | 0 | 未设置 |
DISALLOW | 1 | 不允许 |
ALLOW_WHEN_USING | 2 | 使用小程序时 |
ALLOW | 3 | 允许 |
IFinApplet.IAppletInfo
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
appId | string | 是 | 小程序ID |
name | string | 是 | 小程序名称 |
logo | string | 否 | 小程序logo地址 |
IFinAppProxy.ISettingListParams
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
applet | IFinApplet.IAppletInfo | 是 | 小程序信息 |
scopes | IFinApplet.IScope[] | 是 | 权限列表 |
# 5.GrayReleaseHandler
灰度发布相关的代理类
// namespace IFinProxyHandlerItem export class GrayReleaseHandler { /** * 当获取小程序信息时会调用该方法,可以自定义灰度发布的数据,sdk 会将自定义数据和内置数据合并发送,当属性名相同时,使用自定义的数据 * @param appId * @param apiServer * @returns 需要拼接到灰度发布配置的数据 */ public getGrayExtension(appId: string, apiServer: string): Record<string, string> }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinProxyHandlerItem } from '@finclip/sdk' class GrayReleaseHandler extends IFinProxyHandlerItem.GrayReleaseHandler { getGrayExtension(appId: string, apiServer: string): Record<string, string> { return { 'customKey': 'customValue', 'xUserId': '130000000' } } } FinAppProxyHandlerManager.grayReleaseHandler = new GrayReleaseHandler()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class GrayReleaseHandler { /** * 当获取小程序信息时会调用该方法,可以自定义灰度发布的数据,sdk 会将自定义数据和内置数据合并发送,当属性名相同时,使用自定义的数据 */ getGrayExtension?: ( appId: string, apiServer: string,) => Record<string, string> }
已复制代码
示例代码:
client.proxyHandlerManager.grayReleaseHandler.getGrayExtension = ( appId: string, apiServer: string) => { return { customName: 'customName' } }
已复制代码
# 6.AppletLifeCycleHandler
小程序生命周期相关
// namespace IFinProxyHandlerItem export class AppletLifeCycleHandler { /** * 当小程序打开时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onOpen(appId: string, apiServer: string) /** * 当小程序初始化完成时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onInitCompletion(appId: string, apiServer: string) /** * 当小程序关闭时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onClose(appId: string, apiServer: string) /** * 当小程序发生错误时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 * @param code 错误代码。 * @param message 错误信息。 */ public onError(appId: string, apiServer: string, code: string, message: string) /** * 当小程序准备就绪时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onReady(appId: string, apiServer: string) /** * 当小程序显示时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onShow(appId: string, apiServer: string) /** * 当小程序隐藏时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onHide(appId: string, apiServer: string) /** * 当小程序销毁时触发。 * @param appId 小程序的 ID。 * @param apiServer 与小程序关联的 API 服务器。 */ public onDestroy(appId: string, apiServer: string) }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinProxyHandlerItem } from '@finclip/sdk' import { promptAction } from '@kit.ArkUI' class AppletLifeCycleProxy extends IFinProxyHandlerItem.AppletLifeCycleHandler { onOpen(appId: string, apiServer: string) { this.promptMsg(`${appId} onOpen`) } onInitCompletion(appId: string, apiServer: string) { this.promptMsg(`${appId} onInitCompletion`) } onClose(appId: string, apiServer: string) { this.promptMsg(`${appId} onClose`) } onError(appId: string, apiServer: string, code: string, message: string) { this.promptMsg(`${appId} onError,code:${code},message:${message}`) } onReady(appId: string, apiServer: string) { this.promptMsg(`${appId} onReady`) } onShow(appId: string, apiServer: string) { this.promptMsg(`${appId} onShow`) } onHide(appId: string, apiServer: string) { this.promptMsg(`${appId} onHide`) } onDestroy(appId: string, apiServer: string) { this.promptMsg(`${appId} onDestroy`) } private promptMsg(message: string) { promptAction.showToast({ message }) } } FinAppProxyHandlerManager.appletLifeCycleHandler = new AppletLifeCycleProxy()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class AppletLifeCycleHandler { onOpen?: (appId: string, apiServer: string) => void // 小程序打开 onInitCompletion?: (appId: string, apiServer: string) => void // 小程序初始化完成 onClose?: (appId: string, apiServer: string) => void // 小程序关闭 onError?: (appId: string, apiServer: string, code: string, message: string) => void // 小程序报错 onReady?: (appId: string, apiServer: string) => void // 小程序页面首次渲染完成 onDestroy?: (appId: string, apiServer: string) => void // 小程序销毁 }
已复制代码
# 7.CustomLayoutHandler
自定义布局相关的代理类
// namespace IFinProxyHandlerItem export class CustomLayoutHandler { /** * 自定义分包下载错误页 * @returns 自定义分包下载错误页 builder */ public getDownloadSubpackageFileFailedLayout(): ((appId: string, apiServer: string, path: string, reload: () => void) => void) | void /** * 自定义加载错误页 * @returns 自定义加载错误页 builder */ public getLoadFailedLayout(): ((appId: string, apiServer: string, title: string, label: string) => void) | void /** * 当页面准备完成触发,该函数结束后销毁 loading 组件 * @returns */ public async onPageLoadingLayoutReady(): Promise<void> /** * 当小程序准备完成触发,该函数结束后销毁 loading 页 * @returns */ public async onLoadingLayoutReady(): Promise<void> /** * 自定义页面 loading 组件 * @returns 自定义页面 loading 的 builder */ public getPageCustomLoadingLayout(): ((appId: string, apiServer: string, path: string) => void) | void /** * 获取自定义 loading 页的布局方法 * @returns 自定义 loading 页 builder */ public getCustomLoadingLayout(): (() => void) | void /** * 获取自定义 Toast 方法 * @returns 自定义 Toast builder */ public getCustomToastLayout(): (() => void) | void /** * 获取自定义覆盖物 builder,会渲染在小程序页面上层 * @returns 自定义覆盖物 builder */ public getCustomOverlayLayout(): ((appId: string, apiServer: string) => void) | void }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinProxyHandlerItem } from '@finclip/sdk' import { CustomToast } from '../customLayout/customToast' import { CustomOverlayLayout } from '../customLayout/customOverlayLayout' import { DownloadSubpackageFileFailedLayout } from '../customLayout/DownloadSubpackageFileFailedLayout' import { LoadFailedLayout } from '../customLayout/LoadFailedLayout' import { CustomLoadingLayout, PageCustomLoadingLayout } from '../customLayout/LoadingLayout' class CustomLayoutHandler extends IFinProxyHandlerItem.CustomLayoutHandler { /** * 自定义分包下载错误页 * @returns 自定义分包下载错误页 builder */ getDownloadSubpackageFileFailedLayout(): ((appId: string, apiServer: string, path: string, reload: () => void) => void) | void { return DownloadSubpackageFileFailedLayout } /** * 自定义加载错误页 * @returns 自定义加载错误页 builder */ getLoadFailedLayout(): ((appId: string, apiServer: string, title: string, label: string) => void) | void { return LoadFailedLayout } onPageLoadingLayoutReady(): Promise<void> { return new Promise((resolve) => { setTimeout(() => { resolve() }, 200) }) } onLoadingLayoutReady(): Promise<void> { return new Promise((resolve) => { setTimeout(() => { resolve() }, 200) }) } getPageCustomLoadingLayout(): ((appId: string, apiServer: string, path: string) => void) | void { return PageCustomLoadingLayout } getCustomLoadingLayout(): (() => void) | void { return CustomLoadingLayout } getCustomToastLayout(): (() => void) | void { return CustomToast } getCustomOverlayLayout(): ((appId: string, apiServer: string) => void) | void { return CustomOverlayLayout } } FinAppProxyHandlerManager.customLayoutHandler = new CustomLayoutHandler()
已复制代码
// DownloadSubpackageFileFailedLayout.ets @Builder export function DownloadSubpackageFileFailedLayout(appId: string, apiServer: string, path: string, reload: () => void) { CustomViewComponent({ appId, apiServer, path, reload }) } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop path: string reload?: () => void build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { Text('appId: ' + this.appId) Text('apiServer: ' + this.apiServer) Text('path: ' + this.path) Button('重新加载').onClick(() => { this.reload?.() }) } } .backgroundColor(Color.White) .width('100%') .height('100%') } }
已复制代码
// LoadFailedLayout.ets @Builder export function LoadFailedLayout(appId: string, apiServer: string, title: string, label: string) { CustomViewComponent({ appId, apiServer, title, label }) } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop title: string @Prop label: string build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { Text('appId: ' + this.appId) Text('apiServer: ' + this.apiServer) Text('title: ' + this.title) Text('label: ' + this.label) } } .backgroundColor(Color.White) .width('100%') .height('100%') } }
已复制代码
// LoadingLayout.ets @Builder export function PageCustomLoadingLayout(appId: string, apiServer: string, path: string) { CustomViewComponent({ appId, apiServer, path, }) } @Builder export function CustomLoadingLayout() { CustomViewComponent() } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop path: string build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { if (this.path) { Text('页面自定义 loading') Text('appId: ' + this.appId) Text('apiServer: ' + this.apiServer) Text('path: ' + this.path) } else { Text('自定义 loading 页') } } } .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .backgroundColor(this.path ? Color.Red : Color.Green) .width('100%') .height('100%') } }
已复制代码
// CustomToast.ets import { IFinAppProxy } from '@finclip/sdk'; @Builder export function CustomToast() { CustomViewComponent() } @Component struct CustomViewComponent { @Consume toastInfo: IFinAppProxy.ICustomToastLayoutParams build() { this.toastWithMask() } @Builder toastImage() { if (this.toastInfo.image) { Image(this.toastInfo.image) .width(40) .height(40) } else if (this.toastInfo.icon) { if (this.toastInfo.icon === 'loading') { Text('loading 图案') } if (this.toastInfo.icon === 'success') { Text('success 图案') } if (this.toastInfo.icon === 'error') { Text('error 图案') } } } @Builder toast() { if (this.toastInfo.icon === 'none') { Column() { Text(this.toastInfo.title) .fontSize(14) .fontColor('rgba(255, 255, 255, 0.9)') .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(2) .textAlign(TextAlign.Center) } .constraintSize({ maxWidth: 200, minHeight: 48 }) .padding({ left: 12, right: 12, top: 14, bottom: 14 }) // 加一个占位空间,让垂直居中稍微靠上 .margin({ bottom: 120 }) .backgroundColor('rgba(0, 0, 0, 0.7)') .align(Alignment.Center) .justifyContent(FlexAlign.Center) .opacity(1) .borderRadius(10) .clip(true) } else { Column() { this.toastImage() Text(this.toastInfo.title) .fontSize(14) .fontColor('rgba(255, 255, 255, 0.9)') .margin({ top: 12 }) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(2) .textAlign(TextAlign.Center) } .width(130) .height(130) .padding({ left: 14, right: 14 }) // 加一个占位空间,让垂直居中稍微靠上 .margin({ bottom: 120 }) .backgroundColor('rgba(0, 0, 0, 0.7)') .align(Alignment.Center) .justifyContent(FlexAlign.Center) .opacity(1) .borderRadius(10) .clip(true) } } @Builder toastWithMask() { Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { this.toast() } .width('100%') .height('100%') .backgroundColor('transparent') // 稍微小于 modal 和 actionsheet .zIndex(110) .position({ top: 0, left: 0 }) .hitTestBehavior(this.toastInfo.mask ? HitTestMode.Default : HitTestMode.Transparent) } }
已复制代码
// customOverlayLayout.ets @Builder export function CustomOverlayLayout(appId: string, apiServer: string) { Column() { Text('CustomLayout') Text(appId) Text(apiServer) } }
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class CustomLayoutHandler { // 获取自定义 loading 页的布局方法 getCustomLoadingLayout?: () => (() => void) | void // 自定义页面 loading 组件 getPageCustomLoadingLayout?: () => ((appId: string, apiServer: string, path: string) => void) | void // 当小程序准备完成触发,该函数结束后销毁 loading 页 onLoadingLayoutReady: () => Promise<void> = async () => {} // 当页面准备完成触发,该函数结束后销毁 loading 组件 onPageLoadingLayoutReady: () => Promise<void> = async () => {} // 自定义分包下载错误页 getDownloadSubpackageFileFailedLayout?: () => ((appId: string, apiServer: string, path: string, reload: () => void) => void) | void // 自定义加载错误页 getLoadFailedLayout?: () => ((appId: string, apiServer: string, title: string, label: string) => void) | void }
已复制代码
示例代码1(小程序 loading)
client.proxyHandlerManager.customLayoutHandler.getCustomLoadingLayout = () => customLoading // 如果小程序启动依赖某些异步数据才渲染,比如请求等,这时候小程序可能还是处于无数据的状态,可以通过延迟调用 resolve 的方式来延缓 loading 页销毁时机 client.proxyHandlerManager.customLayoutHandler.onLoadingLayoutReady = () => { return new Promise((resolve) => { setTimeout(() => { resolve() }, 200) }) } @Builder function customLoading() { CustomViewComponent() } // 该组件会渲染在整个 loading 页面 @Component struct CustomViewComponent { @Consume layoutParams: IFinAppProxy.ICustomLoadingLayoutParams build() { Column() { Image(this.layoutParams.logo) Text(this.layoutParams.name) } } }
已复制代码
示例代码2(页面 loading)
client.proxyHandlerManager.customLayoutHandler.getPageCustomLoadingLayout = () => customLoading // 如果小程序启动依赖某些异步数据才渲染,比如请求等,这时候小程序页面可能还是处于无数据的状态,可以通过延迟调用 resolve 的方式来延缓 loading 页销毁时机 client.proxyHandlerManager.customLayoutHandler.onPageLoadingLayoutReady = () => { return new Promise((resolve) => { setTimeout(() => { resolve() }, 200) }) } // 这里会传入小程序的页面的信息,开发者可以根据 path 来自定义不同的 loading 组件 @Builder function customLoading(appId: string, apiServer: string, path: string) { CustomViewComponent({ appId, apiServer, path }) } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop path: string build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { Text('path: ' + this.path) } } .backgroundColor(Color.White) .width('100%') .height('100%') } }
已复制代码
示例代码3(自定义分包下载错误页)
client.proxyHandlerManager.customLayoutHandler.getDownloadSubpackageFileFailedLayout = () => customLayout // 这里会传入小程序的页面的信息 @Builder function customLayout(appId: string, apiServer: string, path: string, reload: () => void) { CustomViewComponent({ appId, apiServer, path, reload }) } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop path: string reload:() => void // 重新加载 build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { Text('path: ' + this.path) }.onClick(()=>{ this.reload?.() }) } .backgroundColor(Color.White) .width('100%') .height('100%') } }
已复制代码
示例代码4(自定义加载错误页)
client.proxyHandlerManager.customLayoutHandler.getLoadFailedLayout = () => customLayout // 这里会传入小程序的页面的信息 @Builder function customLayout(appId: string, apiServer: string, title: string, label: string) { CustomViewComponent({ appId, apiServer, title, label }) } @Component struct CustomViewComponent { @Prop appId: string @Prop apiServer: string @Prop title: string @Prop label: string build() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) { Column() { Text('appletName: ' + this.title) Text('label: ' + this.label) Text('apiServer: ' + this.apiServer) Text('appId: ' + this.appId) } } .backgroundColor(Color.Green) } }
已复制代码
IFinAppProxy.ICustomLoadingLayoutParams
属性 | 类型 | 描述 |
---|---|---|
name | String | 小程序名称,当未获取到小程序详情时,默认为空 |
logo | ResourceStr | 小程序图标,当未获取到小程序详情或者小程序详情中的小程序图标字段为空会返回一个默认的图标,开发者可以自行选择是否使用 |
appId | String | 小程序 appId,当未获取到小程序详情时,默认为空 |
apiServer | String | 小程序 apiServer,当未获取到小程序详情时,默认为空 |
# 8.ButtonOpenTypeHandler
小程序中的 button 有一系列的open-type事件,有部分行为需要App来实现,所以也会通过代理方法来触发对应的事件
// namespace IFinProxyHandlerItem export class ButtonOpenTypeHandler { /** * 调用获取用户信息的Api(getUserProfile) 时,会触发该代理方法。 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns Promise<IFinApplet.IUserProfile | void> * */ public async getUserProfile(appId: string, apiServer: string): Promise<IFinApplet.IUserProfile | void> /** * 调用获取用户信息API(getUserInfo) 或者 点击open-type 属性为 getUserInfo 的 Button 时触发该代理事件 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns Promise<IFinApplet.IUserInfo | void> * */ public async getUserInfo(appId: string, apiServer: string): Promise<IFinApplet.IUserInfo | void> }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinApplet, IFinProxyHandlerItem } from '@finclip/sdk' class ButtonOpenTypeHandler extends IFinProxyHandlerItem.ButtonOpenTypeHandler { async getUserProfile(appId: string, apiServer: string): Promise<IFinApplet.IUserProfile | void> { return { nickName: "昵称", avatarUrl: "头像地址", gender: "性别", province: "省份", city: "城市", country: "国家", } } async getUserInfo(appId: string, apiServer: string): Promise<IFinApplet.IUserInfo | void> { return { nickName: "昵称", avatarUrl: "头像地址", gender: "性别", province: "省份", city: "城市", country: "国家", } } } FinAppProxyHandlerManager.buttonOpenTypeHandler = new ButtonOpenTypeHandler()
已复制代码
1.1.1 之前的实现方式,1.1.1 之后不推荐使用
class ButtonOpenTypeHandler { /** * 调用获取用户信息API(getUserInfo) 或者 点击open-type属性为getUserInfo的Button时触发该代理事件 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns Promise<IFinApplet.IUserInfo | void> * */ getUserInfo?: (appId: string, apiServer: string) => Promise<IFinApplet.IUserInfo | void> /** * 调用获取用户信息的Api(getUserProfile) 时,会触发该代理方法。 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns Promise<IFinApplet.IUserProfile | void> * */ getUserProfile?: (appId: string, apiServer: string) => Promise<IFinApplet.IUserProfile | void> }
已复制代码
示例代码:
client.proxyHandlerManager.buttonOpenTypeHandler.getUserInfo = async ( appId: string, apiServer: string) => { return { nickName: "昵称", avatarUrl: "头像地址", gender: "性别", province: "省份", city:"城市", country: "国家", } } client.proxyHandlerManager.buttonOpenTypeHandler.getUserProfile = async ( appId: string, apiServer: string) => { return { nickName: "昵称", avatarUrl: "头像地址", gender: "性别", province: "省份", city:"城市", country: "国家", } }
已复制代码
IFinApplet.IUserInfo
属性 | 类型 |
---|---|
nickName | String |
avatarUrl | String |
gender | String |
province | String |
city | String |
country | String |
IFinApplet.IUserProfile
type IUserInfo = string | number | boolean | null | Serializable[] | { [key: string]: Serializable }
已复制代码
# 9.onAppBackPressHandler
侧滑代理
// namespace IFinProxyHandlerItem export class onAppBackPressHandler { /** * 当用户侧滑时触发 * @param appId 小程序 id * @param apiServer 小程序 apiServer * @returns 返回 true 表示宿主自行处理,返回 false 表示宿主处理完,仍执行后续的默认操作 */ public onBackPress(appId: string, apiServer: string): boolean | void }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinProxyHandlerItem } from '@finclip/sdk' import { promptAction } from '@kit.ArkUI' class onAppBackPressHandler extends IFinProxyHandlerItem.onAppBackPressHandler { onBackPress(appId: string, apiServer: string) { // 仅对小程序生效 // 返回 true 表示宿主自行处理 // 返回 false 表示宿主处理完,仍执行后续的默认操作 this.promptMsg(`触发了侧滑代理`) return false } private promptMsg(message: string) { promptAction.showToast({ message }) } } FinAppProxyHandlerManager.onAppBackPressHandler = new onAppBackPressHandler()
已复制代码
# 10. LogHandler
日志的代理类
// namespace IFinProxyHandlerItem export class LogHandler { /** * 是否开启控制台输出,默认 false */ public isConsoleLog: boolean = false; /** * 是否写入文件,默认 true */ public writeFile: boolean = true; /** * 设置日志文件保留时间,单位为秒(默认10天,至少为1天) */ public logFileAliveDuration: number = 60 * 60 * 24 * 10 /** * 日志输出的完整的沙箱路径 * 默认路径 /data/app/el2/100/base/包名/haps/entry/files/Applet/logs */ public logDir?: string /** * 触发 log 时会执行该方法,如果想自行处理日志文件,可以将 writeFile 设置为 false,然后在该方法处理日志内容 */ public onLog(level: IFinAppConfig.ILogLevel, log: string) }
已复制代码
示例代码
import { FinAppProxyHandlerManager, IFinAppConfig, IFinProxyHandlerItem } from '@finclip/sdk'; class LogHandler extends IFinProxyHandlerItem.LogHandler { isConsoleLog: boolean = true; writeFile: boolean = true; onLog(level: IFinAppConfig.ILogLevel, log: string): void { console.log(`level:${level},log:${log}`) } } FinAppProxyHandlerManager.logHandler = new LogHandler()
已复制代码