开放定制化JSAPI

当你创建集成应用是为了提供JSAPI供前端小程序/H5应用使用,你将需要使用以下的扩展能力。

专有钉钉平台提供了以下几个接口组件:

  • JsServicePlugin:管理注册扩展jsapi的入口类。
  • JsModule:定义扩展jsapi的具体实现类。
  • JSRequest:jsapi调用请求对象,可获取请求入参等信息。
  • JsResponse:sdk返回执行结果使用。

为了更好的说明如何定义扩展JSAPI,我们假设以下需求场景:

  • (假设)我们需要开发一个文档类的定制扩展模块,文档的展示等是通过OA小程序应用展示业务逻辑;OA小程序需要下载、打开并编辑一个文档,而文档的编辑是使用Native代码开发,Native代码就是我们开发的SDK;
  • 打开文档的入口在小程序中,因此需要定义openfile的jsapi;
  • 编辑完成后需要将结果返回给小程序,即需要通过startActivityForResult将结果返回给小程序;

    定义JsModule

    定义打开文档的扩展jsapi:file.open。
    示例JsModule的定义:

    1. @JSModule
    2. public class JsModuleFile extends JsModule {
    3. @JSMethod("file.open")
    4. public void fileOpen(final JsRequest jsRequest, final JsResponse jsResponse) {
    5. Intent intent = new Intent(jsRequest.context, EditDocActivity.class);
    6. if (jsRequest.params != null) {
    7. intent.putExtra("filePath", jsRequest.params.optString("filePath"));
    8. intent.putExtra("token", jsRequest.params.optString("token"));
    9. }
    10. startActivityForResult(jsRequest, jsResponse, intent, REQUEST_CODE);
    11. // 此处不返回结果,在onActivityResult返回结果
    12. }
    13. @JSMethod("file.delete")
    14. public void fileDelete(final JsRequest jsRequest, final JsResponse jsResponse) {
    15. if (jsRequest.params != null) {
    16. intent.putExtra("filePath", jsRequest.params.optString("filePath"));
    17. //....
    18. }
    19. // 对于常规的扩展jsapi,比如文件删除等,执行完后直接通过JsResponse通知结果
    20. jsResponse.notifySuccess(null);
    21. }
    22. }

    关键步骤:

  • @JSModule注解:标记Jsapi的扩展类

  • @JSMethod(“api-name”)注解:定义扩展jsapi,注意被标记的函数的返回值、入参必须固定为以下形态:

public void fun(final JsRequest jsRequest, final JsResponse jsResponse) ;

  • JsRequest:可获取前端应用传递过来的参数;
  • JsResponse:返回结果

    onActivityResult

    我们通过startActivityForResult() 打开了EditDocActivity后,需要将EditDocActivity的Result结果返回应前端应用,此时需要使用到onActivityResult函数。

JsModule中提供了两个函数:
‒ startActivityForResult() :用于打开指定Activity;
‒ onActivityResult(): 用于接收Activity的返回result;
请注意,以上两个函数必须配套使用,否则将无法生效。

示例代码:

  • 无论成功还是失败,务必通过JsResponse返回执行结果给前端应用。

    1. @JSModule
    2. public class JsModuleFile extends JsModule {
    3. @Override
    4. public void onActivityResult(int requestCode, int resultCode, Intent intent, JsResponse response) {
    5. super.onActivityResult(requestCode, resultCode, intent, response);
    6. if (requestCode == REQUEST_CODE) {
    7. String result = intent.getStringExtra("result");
    8. JSONObject jsonObject = new JSONObject();
    9. jsonObject.put("xxxx", result);
    10. response.notifySuccess(jsonObject);
    11. }
    12. }
    13. }

注意:假如打开的Activity比较耗内存,比如Camera、文档类,如果使用startActivity的方式,可能会造成返回后小程序页面被系统回收清理,因此建议优先使用startActivityForResult()方式打开Activity。

使用JsServicePlugin

定义了JsModule或JsSubject之后,需要将这些对象初始化注入到JsServicePlugin中才能最终生效。

客户端代码示例:

  1. @Extension(id = "dingding_demo_jsbridge", target = JsServicePlugin.EXTENSION_POINT_ID)
  2. public class DemoJSServicePlugin extends JsServicePlugin {
  3. @Override
  4. public void initJsModules() {
  5. JsModuleFile file = new JsModuleFile();
  6. registerJsApi("file.open", file);
  7. registerJsApi("file.delete", file);
  8. }
  9. @Override
  10. public void initJsSubjects() {
  11. }
  12. @Override
  13. public void onDestroy() {
  14. // 清理工作
  15. }
  16. }
  • @Extension注解:
    • id:当前扩展的id,由开发者自定义,需要保证唯一性,否则会编译失败或导致功能异常,推荐带上特殊标识,例如专有钉钉的开发者可以带上dingding前缀。
    • target:当前扩展对应的扩展点id,一般为其父类中的常量,例子中为JsServicePlugin.EXTENSION_POINT_ID

前端调用JSAPI的说明

调用JsModle定义的api

  1. // JSAPI: exclusiveInvoke
  2. // 入参:
  3. // - api:sdk定义的jsapi,比如 "file.open"
  4. // - params:请求的参数
  5. import exclusiveInvoke from 'gdt-jsapi/exclusiveInvoke';
  6. exclusiveInvoke({
  7. api: 'file.open',
  8. params: {
  9. filePath: 'xxxxx',
  10. toekn: 'xxxxx'
  11. }
  12. })