javaRegisterCode static method

String javaRegisterCode(
  1. Module module,
  2. UniAPIOptions options
)

Implementation

static String javaRegisterCode(Module module, UniAPIOptions options) {
  return CodeTemplate(children: [
    CommentUniAPI(),
    EmptyLine(),
    JavaPackage(module.inputFile, options),
    EmptyLine(),
    JavaImport(fullClassName: 'java.util.List'),
    JavaImport(fullClassName: 'java.util.ArrayList'),
    JavaImport(fullClassName: 'java.util.Map'),
    JavaImport(fullClassName: 'java.util.HashMap'),
    JavaImport(fullClassName: 'android.util.Log'),
    JavaImport(fullClassName: 'io.flutter.plugin.common.BasicMessageChannel'),
    JavaImport(fullClassName: 'io.flutter.plugin.common.BinaryMessenger'),
    JavaImport(
        fullClassName: 'io.flutter.plugin.common.StandardMessageCodec'),
    JavaImport(
        fullClassName:
            '${options.javaPackageName}.${options.javaUniAPIPrefix}$kUniAPI'),
    JavaImport(
        fullClassName:
            'static ${options.javaPackageName}.$projectName.UniModel.map'),
    JavaCustomNestedImports(module.inputFile, options,
        methods: module.methods, excludeImports: [typeUniCallback]),
    EmptyLine(),
    JavaClass(
        className: '${module.name}Register',
        isPublic: true,
        injectedJavaCodes: (depth) => [
              ...JavaCollectionCloneFunction()
                  .handlerJavaCollectionType(methods: module.methods),
              JavaFunction(
                  depth: depth,
                  functionName: 'setup',
                  isPublic: true,
                  params: [
                    Variable(
                        AstCustomType('BinaryMessenger'), 'binaryMessenger'),
                    Variable(AstCustomType(module.name), 'impl')
                  ],
                  isStatic: true,
                  body: (depth) => module.methods
                      .where((method) => method.name != module.name)
                      .map((method) => ScopeBlock(
                          depth: depth + 1,
                          body: (depth) => [
                                OneLine(
                                    depth: depth,
                                    body:
                                        'BasicMessageChannel<Object> channel ='),
                                OneLine(
                                    depth: depth + 2,
                                    body:
                                        'new BasicMessageChannel<>(binaryMessenger, "${_getModuleRegisterChannelName(module, method)}", new StandardMessageCodec());'),
                                IfBlock(
                                    OneLine(
                                        body: 'impl != null',
                                        hasNewline: false), (depth) {
                                  final ret = <CodeUnit>[];
                                  ret.add(OneLine(
                                      depth: depth,
                                      body:
                                          '${options.javaUniAPIPrefix}$kUniAPI.registerModule(impl);'));
                                  ret.add(OneLine(
                                      depth: depth,
                                      body:
                                          'channel.setMessageHandler((message, reply) -> {'));
                                  ret.add(OneLine(
                                      depth: depth + 1,
                                      body:
                                          'Map<String, Object> wrapped = new HashMap<>();'));
                                  ret.add(OneLine(
                                      depth: depth + 1, body: 'try {'));
                                  ret.add(OneLine(
                                      depth: depth + 2,
                                      body:
                                          'Map<String, Object> params = (Map<String, Object>) message;'));

                                  // 将 Channel 调用传过来的数据转换成方法调用参数
                                  // 常规参数解析
                                  for (final param in method.parameters) {
                                    if (param.type.astType() ==
                                        typeUniCallback) {
                                      // 这里第二个参数,取出的是对应 Callback 的唯一名称,这个从 Native 带到 Dart 再带回来
                                      final callbackClassName =
                                          '${module.name}.${JavaClassUniCallback.getName(method.name, param.name)}';
                                      ret.add(OneLine(
                                          depth: depth + 2,
                                          body:
                                              '$callbackClassName ${param.name} = new ${module.name}.${JavaClassUniCallback.getName(method.name, param.name)}(binaryMessenger, (String) params.get("${param.name}"));'));
                                    } else {
                                      final decoded = param.type
                                          .convertJavaJson2Obj(
                                              vname:
                                                  'params.get("${param.name}")');
                                      ret.add(OneLine(
                                          depth: depth + 2,
                                          body:
                                              '${param.type.javaType()} ${param.name} = params.containsKey("${param.name}") ? $decoded;'));
                                    }
                                  }

                                  // 生成实际方法调用
                                  var paramsList = method.parameters
                                      .map((e) => e.name)
                                      .toList()
                                      .join(', ');
                                  if (!method.isAsync) {
                                    final call = OneLine(
                                        depth: depth + 2,
                                        body:
                                            'impl.${method.name}($paramsList);');

                                    if (method.returnType is AstVoid) {
                                      ret.add(call);
                                    } else {
                                      ret.add(OneLine(
                                          depth: depth + 2,
                                          body:
                                              '${method.returnType.javaType()} output = ${OneLine(body: call.body).build().replaceAll('\n', '')}'));
                                    }
                                    final isCustomType = method.returnType
                                        .realType() is AstCustomType;

                                    // != null 表达式
                                    final neqNullExp = isCustomType
                                        ? 'output != null ? '
                                        : '';

                                    // null 表达式
                                    final nullExp =
                                        isCustomType ? ' : null' : '';
                                    ret.add(OneLine(
                                        depth: depth + 2,
                                        body:
                                            'wrapped.put("${Keys.result}", $neqNullExp${method.returnType.realType().convertJavaObj2Json('output')}$nullExp);'));
                                  } else {
                                    final retValue = method.returnType
                                        .realType()
                                        .convertJavaObj2Json('ret');
                                    paramsList +=
                                        '${paramsList.isNotEmpty ? ', ' : ''}(ret) -> {';

                                    ret.add(OneLine(
                                        depth: depth + 2,
                                        body:
                                            'impl.${method.name}($paramsList'));

                                    //构造 try{} catch{}
                                    ret.add(OneLine(
                                        depth: depth + 3, body: 'try {'));
                                    ret.add(OneLine(
                                        depth: depth + 4,
                                        body:
                                            'wrapped.put("result", $retValue);'));
                                    ret.add(OneLine(
                                        depth: depth + 4,
                                        body: 'reply.reply(wrapped);'));
                                    ret.addAll(_buildJavaCatchErrorTemplate(
                                        isAsync: method.isAsync,
                                        ignoreError: method.ignoreError,
                                        baseDepth: depth + 2));
                                  }

                                  ret.addAll(_buildJavaCatchErrorTemplate(
                                      isAsync: method.isAsync,
                                      ignoreError: method.ignoreError,
                                      baseDepth: depth));

                                  return ret;
                                },
                                    elseContent: (depth) => [
                                          OneLine(
                                              depth: depth,
                                              body:
                                                  'channel.setMessageHandler((message, reply) -> {});')
                                        ],
                                    depth: depth)
                              ]))
                      .toList()),
              EmptyLine(),
              JavaFunction(
                  depth: depth,
                  functionName: 'wrapError',
                  isPrivate: true,
                  isStatic: true,
                  params: [Variable(AstCustomType('Throwable'), 'exception')],
                  returnType: AstMap(keyType: AstString()),
                  body: (depth) => [
                        OneLine(
                            depth: depth + 1,
                            body:
                                'Map<String, Object> errorMap = new HashMap<>();'),
                        OneLine(
                            depth: depth + 1,
                            body:
                                'errorMap.put("message", exception.toString());'),
                        OneLine(
                            depth: depth + 1,
                            body:
                                'errorMap.put("code", exception.getClass().getSimpleName());'),
                        OneLine(
                            depth: depth + 1,
                            body: 'errorMap.put("details", null);'),
                        OneLine(depth: depth + 1, body: 'return errorMap;'),
                      ])
            ])
  ]).build();
}