FinClip为企业提供小程序生态圈技术产品,开发者可在FinClip小程序开发帮助中心找到相关FinClip小程序指引

# 代理方法

小程序中部分业务是抽象定义的,这些抽象的业务通过接口的形式暴露给了外部,外部可以自行实现具体的业务逻辑。

所有代理类均是在调用 FinAppClient.init 方法返回出来 FinAppClient 实例的 proxyHandlerManager 属性上,示例代码中的 client 即为 FinAppClient 的实例

函数签名如果是需要返回 boolean 类型表示是否需要阻止默认行为,如果需要阻止就返回 true,否则则返回 false

函数里的参数 appIdapiServer 均为触发的小程序的信息,可以根据这两个数据来对不同的小程序来执行不同的逻辑

# 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: "国家",
 }
}
© FinClip with ❤ , Since 2017