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

# API/组件自定义

如果小程序里需要调用一些宿主 App 提供的能力,而 FinClip 小程序 SDK 未实现或无法实现时,就可以通过注册自定义 API 来实现,使得小程序里也能够调用 App 中注册的 API 了。

当然,要使用一些未实现或无法实现的组件时,也可以注册自定义组件。

注册自定义 API 分两个场景:

  1. 注册给原生小程序使用的自定义 API;
  2. 注册给小程序中 WebView 组件加载的 H5 使用的自定义 API。

# 1. 自定义小程序API

注册自定义小程序api以及使用自定义小程序api有四步:

  • 1.实现自定义api
  • 2.注册自定义api
  • 3.在小程序配置中声明自定义api
  • 4.小程序中调用自定义api

# 1.1 注册自定义小程序异步API

1)实现自定义异步api。

# 实现自定义小程序异步api示例
public class CustomApi extends BaseApi {

    public CustomApi(Context context) {
        super(context);
    }

    @Override
    public String[] apis() {
        return new String[]{"finclipLogin"}; //api名称
    }

    @Override
    public void invoke(String event, JSONObject param, ICallback callback) {
        if ("finclipLogin".equals(event)) {
            val result = JSONObject(); // 模拟获取登录token等信息
            if (result) {
                callback.onSuccess(result)
                return;
            }
            
            callback.onFail();
        }
    }
}

2)将其注册到extensionApiManager中,支持单个注册和批量注册。

注册单个自定义api

    批量注册自定义api

      3)在小程序配置文件中声明自定义api。

      在小程序根目录创建 FinClipConf.js 并进行相应的自定义api配置,或通过 loadExtApi 传入配置参数

      module.exports = {
        extApi:[
          { //普通交互API
            name: 'finclipLogin', //扩展api名 该api必须Native方实现了
            sync: false, //是否为同步api
            params: { //扩展api 的参数格式,可以只列必须的属性
              url: ''
            }
          },
          {
              name: 'finclipTestSync',
              sync: true, // 是否为同步api
              params: {
                  name:'',
                  title:''
              }
          }
        ]
      }
      

      小程序端更多配置信息可参考 ft.loadExtApi

      4)小程序里调用自定义小程序异步api

      ft.finclipLogin({
          url:'https://www.baidu.com',
          success: function (res) {
              console.log("调用customEvent success");
              console.log(res);
          },
          fail: function (res) {
              console.log("调用customEvent fail");
              console.log(res);
          }
      });
      

      注册自定义api(打开原生页面) 比如,注册自定义api 打开支付页面,支付完毕后,再将结果返回。

      首先,实现一个要打开的Activity。(假设所有的支付逻辑都在这个activity)

      public class FinClipPayActivity extends AppCompatActivity {
      
          public static final String PAY_RESULT = "pay_result";
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_fin_clip_pay);
      
              findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      Toast.makeText(FinClipPayActivity.this, getString(R.string.fin_clip_input_content_hint), Toast.LENGTH_SHORT).show();
                      
                      JSONObject payResult = new JSONObject(); // 模拟支付返回结果
                      // 将结果回传,并关闭支付页面
                      String jsonString = payResult.toString();
                      Intent intent = new Intent();
                      intent.putExtra(PAY_RESULT, jsonString);
                      setResult(RESULT_OK, intent);
                      finish();
                  }
              });
          }
      
      }
      

      然后,注册自定义api。

      public class CustomApi extends BaseApi {
      
          public CustomApi(Context context) {
              super(context);
          }
      
          @Override
          public String[] apis() {
              return new String[]{"finclipPay"}; //api名称
          }
      
          @Override
          public void invoke(String event, JSONObject param, ICallback callback) {
              Intent intent = new Intent();
              intent.setClass(mContext, FinClipPayActivity.class);
              String jsonString = param.toString();
              intent.putExtra("jsonString", jsonString);
              callback.startActivityForResult(intent, 100);
          }
          
          @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data, ICallback callback) {
              if (requestCode == 100) {
                  if (resultCode == RESULT_OK && data != null) {
                      String jsonString = data.getStringExtra(EXTRA_PAY_RESULT);
                      try {
                          JSONObject jsonObject = new JSONObject(jsonString);
                          callback.onSuccess(jsonObject);
                      } catch (JSONException e) {
                          e.printStackTrace();
                          callback.onFail();
                      }
                  } else {
                      try {
                          JSONObject jsonObject = new JSONObject();
                          jsonObject.put("errMsg", "支付失败");
                          callback.onFail(jsonObject);
                      } catch (JSONException e) {
                          e.printStackTrace();
                          callback.onFail();
                      }
                  }
              }
          }
      }
      

      再注册自定义api。

      FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new CustomApi(this)); 
      

      小程序的根目录下创建FinClipConf.js,内容示例如下:

      module.exports = {
        extApi:[
         { //支付API
            name: 'finclipPay', //扩展api名 该api必须Native方实现了
            sync: false, //是否为同步api
            params: { //扩展api 的参数格式,可以只列必须的属性
             name: '',
             price:'',
            }
          }
        ]
      }
      

      在小程序中调用自定义api即可。

      ft.finclipPay({
          name:'赛罗-奥特曼',
          price:26.2,
          success: function (res) {
              console.log("调用支付 success");
              console.log(res);
          },
          fail: function (res) {
              console.log("调用支付 fail");
              console.log(res);
          }
      });
      

      # 1.2 注册自定义小程序同步API

      同步api是指在调用的时候可以同步返回结果的自定义api。

      注意:自定义同步api需要继承SyncApi,并重写同步返回的invoke方法。 同步api必须在小程序进程注册才能生效

      1)实现自定义同步api。

      public class CustomApi extends SyncApi {
      
          public CustomApi(Context context) {
              super(context);
          }
      
          @Override
          public String[] apis() {
              return new String[]{"customApi"};
          }
      
          @Nullable
          @Override
          public String invoke(String event, JSONObject param) {
              // {"errMsg": "customApi:ok" , "data": "1"}  // 返回的数据格式是固定的,必须是个json格式且包含"errMsg": "customApi:ok" 这一段
              return getSuccessRes(event).put("data","1").toString(); // 可以借住sdk提供的api完成对数据的组装
              // return getFailureRes(event,"token miss").toString()
          }
      
      }
      

      2)在小程序进程注册同步api

        在小程序进程自定义同步API中,有两种方式获取小程序Activity:

        1. 外部传入,在自定义API类的构造方法中传入;
        2. 直接获取,可以通过FinAppProcessClient.appletProcessActivity获取当前小程序进程对应的Activity。

        3)在小程序配置文件中声明自定义api。

        在小程序根目录创建 FinClipConf.js 并进行相应的自定义api配置,或通过 loadExtApi 传入配置参数

        小程序端更多配置信息可参考 ft.loadExtApi

        module.exports = {
          extApi:[
            { //普通交互API
              name: 'finclipLogin', //扩展api名 该api必须Native方实现了
              sync: false, //是否为同步api
              params: { //扩展api 的参数格式,可以只列必须的属性
                url: ''
              }
            },
            {
                name: 'finclipTestSync',
                sync: true, // 是否为同步api
                params: {
                    name:'',
                    title:''
                }
            }
          ]
        }
        

        4)小程序里调用

        const res = ft.finclipTestSync({'name':'张三', 'title':'Finclip'});
        console.log(res.title);
        

        # 1.3 注册(含自定义sope权限的)自定义api

        自定义api时继承ScopeApi抽象类,示例如下:

        class CustomScopeApi(context: Context) : ScopeApi(context) {
        
            companion object {
                private const val METHOD_LOGIN = "customMethod"
            }
        
            override fun apis(): Array<String> {
                return arrayOf(METHOD_LOGIN)
            }
            
            // 返回绑定的scope对象
            override fun getBindScopes(): Array<AppletScopeBean> {
                // 此处构建自定义的scope对象
                val scope = AppletScopeBean(
                    // 唯一scope值
                    "scope.customScope",
                    // 名字
                    context.getString(R.string.custom_scope_name),
                    // 标题
                    context.getString(R.string.custom_scope_title),
                    // 描述
                    context.getString(R.string.custom_scope_desc)
                )
                return arrayOf(scope)
            }
        
            override fun invoke(event: String, params: JSONObject, callback: ICallback) {
                // 调用checkScope方法会对getBindScopes()方法内返回的自定义Scope权限进行检测、申请
                checkScope(object : Callback {
                    override fun onScopeCallback(allow: Boolean, msg: String) {
                        if (allow) {
                            // 权限申请成功,根据自己需要处理业务逻辑并回调给小程序
                            val result = JSONObject()
                            callback.onSuccess(result)
                        } else {
                            // 权限申请失败,根据自己需要处理业务逻辑并回调给小程序
                            val result = JSONObject()
                            result.put("msg", msg)
                            callback.onFail(result)
                        }
                    }
                })
            }
        }
        

        # 1.4 获取所有已注册的自定义小程序API

        # API

        /**
         * 获取所有已注册的小程序API
         */
        fun getRegisteredApis(): Map<String, IApi>
        

        # 调用示例

          # 2. 自定义 WebView 组件API

          小程序里加载的H5,如果也想调用宿主API的某个能力,就可以利用该方法注册一个API。 目前仅支持注册异步api。

          注册自定义webView Api和使用webView Api有三步:

          • 1.实现自定义api
          • 2.注册自定义api。
          • 3.H5中调用自定义api。

          # 2.1 注册WebView 组件API

          1. 实现自定义api。
          # 自定义api示例
          public class WebApi extends BaseApi {
          
              public WebApi(Context context) {
                  super(context);
              }
          
              @Override
              public String[] apis() {
                  return new String[]{"webApiName"}; //api名称
              }
          
              @Override
              public void invoke(String event, JSONObject param, ICallback callback) {
                  // 调用方法时原生对应的操作
              }
          }
          
          1. 将其注册到extensionWebApiManager中,支持单个注册和批量注册。

          注册单个自定义api

            批量注册自定义api

              3)在H5内调用自定义api

              在H5内引用我们的桥接JSSDK文件,即可调用上面的注册的方法了。

              HTML内调用注册的方法示例:

              window.ft.miniProgram.callNativeAPI('js2AppFunction', {name:'getLocation'}, (result) => {
                  console.log(result)
              });
              

              # 2.2 取消注册 WebView 组件API

              支持单个取消注册和批量取消注册。

              取消单个WebView 组件API

              # 调用示例

                批量取消WebView 组件API

                  # 2.3 获取所有已注册的小程序 WebView API

                  # API

                  /**
                   * 获取所有已注册的网页调用的原生API
                   */
                  fun getRegisteredApis(): Map<String, IApi>
                  

                  # 调用示例

                    # 3. 在小程序进程中注册api

                    正常情况下注册到小程序的api是在主进程调用执行的,当有需要在小程序进程执行的api的时候,需要调用另外的接口去注册。

                      # 4. 原生调用 JS API

                      # API

                      /**
                       * 原生调用JS函数
                       *
                       * @param appId 小程序id
                       * @param funcName JS函数名
                       * @param funcParams JS函数参数
                       * @param webViewId WebView的id
                       * @param callback 回调
                       */
                      fun callJS(appId: String, funcName: String?, funcParams: String?, webViewId: Int, callback: FinCallback<String?>)
                      

                      # 调用示例

                        首先,在H5内引用我们的桥接JSSDK文件。

                        然后,在HTML里注册好方法,比如方法名叫app2jsFunction

                        window.ft.registNativeAPIHandler('app2jsFunction', function(res) {
                            // app2jsFunction callback
                        })
                        

                        # 5. 注册原生组件

                        由于资源有限,livePusher 和livePlayer等原生组件的实现可能需要借助外部的第三方控件,这时候就可以注册原生组件。我们现在支持注册的原生组件有三个:Camera、LivePlayer、LivePusher。

                        # 5.1 实现自定义的原生组件

                        实现INativeView接口

                        # 示例
                        class TestNativeView : INativeView {
                        
                            lateinit var eventChannel: INativeView.EventChannel
                        
                            /**
                             * 创建nativeview
                             * @param params 小程序中传来的参数
                             * @param eventChannel 用来向小程序组件发送事件
                             * @return 创建的view,会填充到小程序里声明组件的位置
                             */
                            override fun onCreateView(
                                context: Context,
                                params: ShowNativeViewParams,
                                eventChannel: INativeView.EventChannel
                            ): View {
                                Log.d(TAG, "onCreateView:${params.nativeViewId}")
                                this.eventChannel = eventChannel
                                return TextView(context).apply {
                                    gravity = Gravity.CENTER
                                    setTextColor(Color.RED)
                                    text = params.params.toString()
                                    setBackgroundColor(Color.GREEN)
                                    setOnClickListener {
                                        eventChannel.send(
                                            "test",
                                            mapOf("time" to System.currentTimeMillis())
                                        )
                                    }
                                }
                            }
                        
                            /**
                             * 更新nativeview
                             * @param params 小程序中传来的参数
                             * @param view 之前创建的view
                             */
                            override fun onUpdateView(context: Context, params: ShowNativeViewParams, view: View) {
                                Log.d(TAG, "onUpdateView:${params.nativeViewId}")
                                params.params?.let { (view as TextView).text = it.toString() }
                            }
                        
                        
                            /**
                             * 销毁nativeview
                             * @param params 小程序中传来的参数
                             * @param view 之前创建的view
                             */
                            override fun onDestroyView(context: Context, nativeViewId: String, view: View) {
                                Log.d(TAG, "onDestroyView:$nativeViewId")
                            }
                        
                        }
                        

                        # 5.2 注册原生组件

                        # API
                        /**
                         * 注册原生组件
                         *
                         * @param type 组件类型
                         * @param cls 组件实现类 需实现INativeView接口
                         */
                        fun registerNativeView(type: String, cls: Class<out INativeView>)
                        
                        # 调用示例
                        # ·Kotlin
                        FinAppClient.nativeViewManager.registerNativeView("native-view", TestNativeView::class.java) 
                        

                        最后,小程序里使用自定义组件即可。

                        <native-view type="native-view" style="left: 0px; top: 0px; width: 100px; height: 100px;">123</native-view>
                        
                        
                        © FinClip with ❤ , Since 2017