# 代理方法
小程序中部分业务是抽象定义的,这些抽象的业务通过接口的形式暴露给了外部,外部可以自行实现具体的业务逻辑。
所有代理类均是在调用 FinAppClient.init
方法返回出来 FinAppClient
实例的 proxyHandlerManager
属性上,示例代码中的 client
即为 FinAppClient
的实例
函数签名如果是需要返回 boolean 类型表示是否需要阻止默认行为,如果需要阻止就返回
true
,否则则返回false
函数里的参数
appId
和apiServer
均为触发的小程序的信息,可以根据这两个数据来对不同的小程序来执行不同的逻辑
# 1. CapsuleHandler
胶囊按钮的代理类
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
更多菜单的代理类
class MoreMenuHandler {
/**
* @param type 菜单按钮的唯一标识
* @param currentPath 小程序当前的页面路径
* @returns
*
*/
onMoreMenuItemClick?: (appId: string, apiServer: string, type: string, currentPath: string) => boolean
/**
* @returns 自定义更多菜单的按钮
*/
getMoreMenuItems: () => IMoreMenuItem[]
}
IMoreMenuItem
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
label | String | 是 | 小程序 id |
icon | ResourceStr | 是 | 菜单按钮的图片资源 |
disableIcon | ResourceStr | 否 | 菜单按钮禁用的图片资源 |
darkIcon | ResourceStr | 否 | 暗黑模式菜单按钮的图片资源 |
disableDarkIcon | ResourceStr | 否 | 暗黑模式菜单按钮禁用的图片资源 |
menuItemId | String | 是 | 菜单按钮的唯一标识,即 onMoreMenuItemClick 参数的 type |
hover | Boolean | 否 | 是否开启 hover 效果 |
disable | Boolean | 否 | 是否禁用 |
示例代码
client.proxyHandlerManager.moreMenuHandler.onMoreMenuItemClick = (appId: string, apiServer: string, type: string, currentPath: string) => {
if(type === 'custom'){
// do something
return true // 阻止默认行为
}
return false
}
client.proxyHandlerManager.moreMenuHandler.getMoreMenuItems = () => {
return [
{
label: '自定义 Btn',
icon: $r('app.media.app_icon'),
menuItemId: 'custom'
}
]
}
# 3. PrivacyHandler
隐私协议的代理类
class PrivacyHandler {
/**
* @param scope 当前请求的权限,如果为空则是在关于页面显示的隐私协议
* @returns IFinApplet.IPrivacy
*/
getPrivacyInfo?: (appId: string, apiServer: string, scope?: string) => IFinApplet.IPrivacy
}
IFinApplet.IPrivacy
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
title | String | 是 | 自定义隐私授权弹窗标题 |
copyWriting | String | 是 | 自定义隐私授权弹窗文案,内容包含 自定义隐私协议文档名称 |
docName | String | 是 | 自定义隐私协议文档名称 |
docUrl | String | 是 | 自定义隐私协议文档链接 |
示例代码
client.proxyHandlerManager.privacyHandler.getPrivacyInfo = (appId: string, apiServer: string, scope?: string) => {
return {
title: '自定义授权弹窗标题',
docName: '自定义隐私协议文档名称',
docUrl: 'https://www.finclip.com',
copyWriting: '自定义授权弹窗文案,隐私协议文档名称为《自定义隐私协议文档名称》'
}
}
# 4. ScopeHandler
自定义权限的代理类
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
// 自定义弹窗,实现方式可以参考示例代码
customView?: () => void
// 注册自定义权限
getCustomScopes: (appId: string, apiServer: string) => IFinApplet.IScope[]
}
IFinApplet. IScope
属性 | 类型 | 是否必填 | 描述 |
---|---|---|---|
scope | String | 是 | 权限标识位 |
title | String | 是 | 权限标题 |
desc | String | 是 | 权限描述 |
scopeStatus | EPermissionState | 是 | 权限状态 |
scopeName | String | 是 | 设置页描述 |
EPermissionState
属性 | 值 | 描述 |
---|---|---|
UNSET | 0 | 未设置 |
DISALLOW | 1 | 不允许 |
ALLOW_WHEN_USING | 2 | 使用小程序时 |
ALLOW | 3 | 允许 |
示例代码
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.customView = 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
# 5.GrayReleaseHandler
灰度发布相关的代理类
class GrayReleaseHandler {
/**
* 当获取小程序信息时会调用该方法,可以自定义灰度发布的数据,sdk 会将自定义数据和内置数据合并发送,当属性名相同时,使用自定义的数据
*/
getGrayExtension?: ( appId: string, apiServer: string,) => Record<string, string>
}
示例代码:
client.proxyHandlerManager.grayReleaseHandler.getGrayExtension = ( appId: string, apiServer: string) => {
return {
customName: 'customName'
}
}
# 6.AppletLifeCycleHandler
小程序生命周期相关
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
自定义布局相关的代理类
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
}
IFinAppProxy.ICustomLoadingLayoutParams
属性 | 类型 | 描述 |
---|---|---|
name | String | 小程序名称,当未获取到小程序详情时,默认为空 |
logo | ResourceStr | 小程序图标,当未获取到小程序详情或者小程序详情中的小程序图标字段为空会返回一个默认的图标,开发者可以自行选择是否使用 |
appId | String | 小程序 appId,当未获取到小程序详情时,默认为空 |
apiServer | String | 小程序 apiServer,当未获取到小程序详情时,默认为空 |
示例代码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%')
}
}
# 8.ButtonOpenTypeHandler
小程序中的 button 有一系列的open-type事件,有部分行为需要App来实现,所以也会通过代理方法来触发对应的事件
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>
}
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 }
示例代码:
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: "国家",
}
}