dartCode static method

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

Implementation

static String dartCode(Module module, UniAPIOptions options) {
  final moduleHasCallback = hasUniCallback(module.methods);
  return CodeTemplate(children: [
    CommentUniAPI(),
    EmptyLine(),
    DartImport(fullClassName: 'dart:async'),
    DartImport(fullClassName: 'package:flutter/services.dart'),
    if (moduleHasCallback) ...[
      DartImport(
          fullClassName: relative(
              '${options.dartOutput}/$projectName/$dotDartFileUniCallback',
              from: dirname(
                  productPath(options.dartOutput, module.inputFile.path)))),
      DartImport(
          fullClassName: relative(
              '${options.dartOutput}/$projectName/$dotDartFileUniCallbackManager',
              from: dirname(
                  productPath(options.dartOutput, module.inputFile.path)))),
      DartImport(
          fullClassName: relative(
              '${options.dartOutput}/$projectName/$dotDartFileCaches',
              from: dirname(
                  productPath(options.dartOutput, module.inputFile.path)))),
    ],
    DartImport(fullClassName: 'package:flutter/foundation.dart'),
    DartImport(
        fullClassName: relative(
            '${options.dartOutput}/$projectName/$dotDartFileprojectNameSnake',
            from: dirname(
                productPath(options.dartOutput, module.inputFile.path)))),
    EmptyLine(),
    DartCustomNestedImports(module.inputFile, options,
        methods: module.methods, excludeImports: [typeUniCallback]),
    EmptyLine(),
    Comment(
        comments: [uniNativeModuleDesc, ...module.codeComments],
        commentType: CommentType.commentTripleBackSlash),
    DartClass(
        className: module.name,
        methods: module.methods,
        injectedJavaCodes: (depth) {
          String generateCallbackName(
                  Module module, Method method, Variable param) =>
              '${module.name}_${method.name}_${param.name}';

          String channelName(Module module, Method method) =>
              '$channelPrefix.${module.name}.${method.name}';

          final ret = <CodeUnit>[];
          for (final method in module.methods) {
            if (method.name == module.name) {
              continue;
            }

            // 生成 UniNativeModule 接口方法
            ret.add(DartFunction(
                depth: depth + 1,
                functionName: method.name,
                params: method.parameters,
                isAsync: true,
                isStatic: true,
                returnType: AstCustomType(typeFuture, generics: [
                  method.returnType.realType()
                ], genericsMaybeNull: [
                  method.returnType.realType() is! AstVoid
                ]),
                body: (depth) {
                  final funcBody = <CodeUnit>[];
                  final callbackParams = method.parameters
                      .where(
                          (param) => param.type.astType() == typeUniCallback)
                      .toList();
                  String? callbackName;
                  String? callbackInstance;

                  if (callbackParams.isNotEmpty) {
                    final callback = callbackParams.first;
                    callbackName =
                        generateCallbackName(module, method, callback);
                    callbackInstance =
                        '${callbackName}_\${${callback.name}.hashCode}';
                    funcBody.add(OneLine(
                        depth: depth + 1,
                        body:
                            "${callback.name}.callbackName = '$callbackInstance';"));
                    funcBody.add(OneLine(
                        depth: depth + 1,
                        body:
                            "uniCallbackCache['$callbackInstance'] = ${callback.name};"));
                  }

                  if (method.parameters.isNotEmpty) {
                    funcBody.add(OneLine(
                        depth: depth + 1,
                        body: 'final Map<String, dynamic> encoded = {};'));
                  }
                  for (final param in method.parameters) {
                    if (param.type.astType() == typeUniCallback) {
                      assert(callbackName != null);
                      assert(callbackInstance != null);
                      funcBody.add(OneLine(
                          depth: depth + 1,
                          body:
                              'encoded["${param.name}"] = \'$callbackInstance\';'));
                    } else {
                      final isNullable = param.type.maybeNull;
                      funcBody.add(OneLine(
                          depth: depth + 1,
                          body:
                              '${isNullable ? 'if (${param.name} != null) ' : ''}encoded["${param.name}"] = ${param.type.convertDartObj2Json(param.name)};'));
                    }
                  }

                  funcBody.add(OneLine(
                      depth: depth + 1,
                      body: kEnableNullSafety
                          ? 'const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ('
                          : 'const BasicMessageChannel<Object> channel = BasicMessageChannel<Object> ('));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body:
                          "'${channelName(module, method)}', StandardMessageCodec());"));
                  if (callbackParams.isNotEmpty) {
                    funcBody.add(OneLine(
                        depth: depth + 1,
                        body: 'UniCallbackManager.getInstance();'));
                  }
                  funcBody.add(OneLine(
                      depth: depth + 1,
                      body: kEnableNullSafety
                          ? 'final Map<Object?, Object?>? replyMap ='
                          : 'final Map<Object, Object> replyMap ='));
                  if (method.parameters.isEmpty) {
                    funcBody.add(OneLine(
                        depth: depth + 2,
                        body: kEnableNullSafety
                            ? 'await channel.send(null) as Map<Object?, Object?>?;'
                            : 'await channel.send(null) as Map<Object, Object>;'));
                  } else {
                    funcBody.add(OneLine(
                        depth: depth + 2,
                        body: kEnableNullSafety
                            ? 'await channel.send(encoded) as Map<Object?, Object?>?;'
                            : 'await channel.send(encoded) as Map<Object, Object>;'));
                  }

                  String connectChannelError() =>
                      'Unable to establish connection on channel : "${channelName(module, method)}" .';
                  String trackErrorExpression(String msg) =>
                      "UniApi.trackError('${module.name}', '${channelName(module, method)}', '$msg');";
                  String ifErrorExpression(String msg) =>
                      "if (error.containsKey('$msg')) errorMsg += '[ \${error['$msg']?.toString() ?? ''} ]';";

                  funcBody.add(OneLine(
                      depth: depth + 1, body: 'if (replyMap == null) {'));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: trackErrorExpression(connectChannelError())));
                  funcBody.add(OneLine(
                      depth: depth + 2, body: 'if (!kReleaseMode) {'));
                  funcBody.add(OneLine(
                      depth: depth + 3, body: 'throw PlatformException('));
                  funcBody.add(OneLine(
                      depth: depth + 4, body: "code: 'channel-error',"));
                  funcBody.add(OneLine(
                      depth: depth + 4,
                      body: "message: '${connectChannelError()}',"));
                  funcBody
                      .add(OneLine(depth: depth + 4, body: 'details: null,'));
                  funcBody.add(OneLine(depth: depth + 3, body: ');'));
                  funcBody.add(OneLine(depth: depth + 2, body: '}'));
                  funcBody.add(OneLine(
                      depth: depth + 1,
                      body: "} else if (replyMap['error'] != null) {"));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: kEnableNullSafety
                          ? "final Map<Object?, Object?> error = (replyMap['${Keys.error}']  as Map<Object?, Object?>);"
                          : "final Map<Object, Object> error = (replyMap['${Keys.error}']  as Map<Object, Object>);"));
                  funcBody.add(OneLine(
                      depth: depth + 2, body: "String errorMsg = '';"));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: ifErrorExpression(Keys.errorCode)));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: ifErrorExpression(Keys.errorMessage)));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: ifErrorExpression(Keys.errorDetails)));
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body: trackErrorExpression(
                          '${method.name}: \$errorMsg);')));
                  funcBody.add(OneLine(
                      depth: depth + 2, body: 'if (!kReleaseMode) {'));
                  funcBody.add(OneLine(
                      depth: depth + 3, body: 'throw PlatformException('));
                  funcBody.add(OneLine(
                      depth: depth + 4,
                      body: "code: error['${Keys.errorCode}'] as String,"));
                  funcBody.add(OneLine(
                      depth: depth + 4,
                      body:
                          "message: error['${Keys.errorMessage}'] as String,"));
                  funcBody.add(OneLine(
                      depth: depth + 4,
                      body: "details: error['${Keys.errorDetails}'],"));
                  funcBody.add(OneLine(depth: depth + 3, body: ');'));
                  funcBody.add(OneLine(depth: depth + 2, body: '}'));
                  funcBody.add(OneLine(depth: depth + 1, body: '} else {'));

                  var ternaryOperatorExpr =
                      method.returnType.realType().maybeNull == true
                          ? '$replyPlaceholder == null ? null : '
                          : '';
                  funcBody.add(OneLine(
                      depth: depth + 2,
                      body:
                          '${method.returnType.realType() is AstVoid ? '' : 'return $ternaryOperatorExpr'}${method.returnType.realType().convertDartJson2Obj()};'));

                  funcBody.add(OneLine(depth: depth + 1, body: '}'));
                  if (method.returnType is! AstVoid) {
                    funcBody.add(OneLine(
                        depth: depth + 1,
                        body:
                            "throw Exception('方法 \"${method.name}\" : 返回类型错误!');"));
                  }
                  return funcBody;
                }));
            ret.add(EmptyLine());
          }

          return ret;
        })
  ]).build();
}