# API/组件自定义

如果小程序里需要调用一些宿主 App 提供的能力,而 “人民网+”小程序 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[]{"customEvent"}; //api名称
    }

    @Override
    public void invoke(String event, JSONObject param, ICallback callback) {
        // 调用方法时原生对应的操作
    }
}

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

注册单个自定义api

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

批量注册自定义api

val apis = listOf<IApi>(CustomApi1(), CustomApi2(), CustomApi3())
FinAppClient.extensionApiManager.registerApis(apis) 
List<IApi> apis = new ArrayList<>();

IApi customApi1 = new CustomApi1();
apis.add(customApi1);

IApi customApi2 = new CustomApi2();
apis.add(customApi2);

IApi customApi3 = new CustomApi3();
apis.add(customApi3);

FinAppClient.INSTANCE.getExtensionApiManager().registerApis(apis); 

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

在小程序根目录创建FinClipConf.js并进行相应的自定义api配置

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

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

ft.Login({
    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);
    }
});

# 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

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        if (FinAppClient.isFinAppProcess(this)) {
            FinAppProcessClient.callback = object : FinAppProcessClient.Callback() {
                @Nullable
                override fun getRegisterExtensionApis(activity: Activity): List<IApi>? {
                    // 在小程序进程中注册小程序扩展API
                    val apis: MutableList<IApi> = ArrayList()
                    val customApi: IApi = CustomApi(activity)
                    apis.add(customApi)
                    return apis
                }

                @Nullable
                override fun getRegisterExtensionWebApis(activity: Activity): List<IApi>? {
                    // 在小程序进程中注册小程序网页调原生API
                    val apis: MutableList<IApi> = ArrayList()
                    val customH5Api: IApi = CustomH5Api(activity)
                    apis.add(customH5Api)
                    return apis
                }
            }
        }
    }
}
public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        if(FinAppClient.INSTANCE.isFinAppProcess(this)){
            FinAppProcessClient.INSTANCE.setCallback(new FinAppProcessClient.Callback() {
                @Nullable
                @Override
                public List<IApi> getRegisterExtensionApis(@NotNull Activity activity) {
                    // 在小程序进程中注册小程序扩展API
                    List<IApi> apis = new ArrayList<>();
                    IApi customApi = new CustomApi(activity);
                    apis.add(customApi);
                    return apis;
                }

                @Nullable
                @Override
                public List<IApi> getRegisterExtensionWebApis(@NotNull Activity activity) {
                    return new ArrayList<>();
                }
            });
        }
    }
}  

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

在小程序根目录创建FinClipConf.js并进行相应的自定义api配置

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

4)小程序里调用

const res = ft.TestSync({'name':'张三', 'title':'“人民网+”'});
console.log(res.title);

# 1.3 取消注册小程序API

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

取消注册的某个api

# 调用示例

FinAppClient.extensionApiManager.unregisterApi(customApi)
FinAppClient.INSTANCE.getExtensionApiManager().unregisterApi(customApi)

批量取消注册的api

# 调用示例

FinAppClient.extensionApiManager.unregisterApis(apis)
FinAppClient.INSTANCE.getExtensionApiManager().unregisterApis(apis); 

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

# API

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

# 调用示例

val apis = FinAppClient.extensionApiManager.getRegisteredApis() 
Map<String, IApi> apis = FinAppClient.INSTANCE.getExtensionApiManager().getRegisteredApis();

# 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

FinAppClient.extensionWebApiManager.registerApi(WebApi(this)) 
FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new WebApi(this)); 

批量注册自定义api

val apis = listOf<IApi>(WebApi1(), WebApi2(), WebApi3())
FinAppClient.extensionWebApiManager.registerApis(apis)
List<IApi> apis = new ArrayList<>();

IApi webApi1 = new WebApi1();
apis.add(webApi1);

IApi webApi2 = new WebApi2();
apis.add(webApi2);

IApi webApi3 = new WebApi3();
apis.add(webApi3);

FinAppClient.INSTANCE.getExtensionWebApiManager().registerApis(apis); 

3)在H5内调用自定义api

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

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

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

# 2.2 取消注册 WebView 组件API

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

取消单个WebView 组件API

# 调用示例
FinAppClient.extensionWebApiManager.unregisterApi(webApi)
FinAppClient.INSTANCE.getExtensionWebApiManager().unregisterApi(webApi)

批量取消WebView 组件API

FinAppClient.extensionWebApiManager.unregisterApis(webApis) 
FinAppClient.INSTANCE.getExtensionWebApiManager().unregisterApis(webApis); 

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

# API

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

# 调用示例

val apis = FinAppClient.extensionWebApiManager.getRegisteredApis() 
Map<String, IApi> apis = FinAppClient.INSTANCE.getExtensionWebApiManager().getRegisteredApis();

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

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

FinAppProcessClient.callback = object : FinAppProcessClient.Callback {
    override fun getRegisterExtensionApis(activity: Activity): List<IApi>? {
        // 在小程序进程中注册小程序扩展API
        return listOf(CustomApi(activity))
    }

    override fun getRegisterExtensionWebApis(activity: Activity): List<IApi>? {
        // 在小程序进程中注册小程序网页调原生API
        return listOf(CustomH5Api(activity))
    }
}
FinAppProcessClient.INSTANCE.setCallback(new FinAppProcessClient.Callback() {
    @Nullable
    @Override
    public List<IApi> getRegisterExtensionApis(@NotNull Activity activity) {
        // 在小程序进程中注册小程序扩展API
        List<IApi> apis = new ArrayList<>();
        IApi customApi = new CustomApi(activity);
        apis.add(customApi);
        return apis;
    }

    @Nullable
    @Override
    public List<IApi> getRegisterExtensionWebApis(@NotNull Activity activity) {
        // 在小程序进程中注册小程序网页调原生API
        List<IApi> apis = new ArrayList<>();
        IApi customH5Api = new CustomH5Api(activity);
        apis.add(customH5Api);
        return apis;
    }
});  

# 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?>)

# 调用示例

FinAppClient.appletApiManager.callJS(
    "appId",
    "funcName",
    "funParams",
    1,
    object : FinCallback<String?> {
        override fun onSuccess(result: String?) {
            Log.d(TAG, "callJS onSuccess : $result")
        }

        override fun onError(code: Int, error: String?) {
            Log.d(TAG, "callJS onError : $code:, $error")
        }

        override fun onProgress(status: Int, info: String?) {
        }
    })
FinAppClient.INSTANCE.getAppletApiManager().callJS(
        "appId",
        "funcName",
        "funParams",
        1,
        new FinCallback<String>() {
            @Override
            public void onSuccess(String result) {
                Log.d(TAG, "callJS onSuccess : " + result);
            }

            @Override
            public void onError(int code, String error) {
                Log.d(TAG, "callJS onError : " + code + ", " + error);
            }

            @Override
            public void onProgress(int status, String info) {

            }
        }); 

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

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

window.ft.miniProgram.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("video", TestNativeView::class.java)