/flutter_platform_code_demo

Primary LanguageDartGNU General Public License v3.0GPL-3.0

flutter_platform_code_demo

尝试利用source_gen自定义代码生成器,解决跨平台开发时差异代码替换的问题。

DEMO使用方法

  1. clone本仓库
  2. 下载依赖flutter pub get
  3. 运行代码生成:
flutter pub run build_runner build
  1. 查看lib目录下生成的*.p.dart代码,或直接运行项目查看效果

指定生成代码平台的方法

方法一

  1. 修改build.yaml,修改最后一行platform: 的值:
      options:
        platform: desktop

当前可选mobiledesktop

  1. 运行代码生成:
flutter pub run build_runner build --delete-conflicting-outputs

方法二

直接在代码生成命令中加入options覆盖参数:

  • desktop:
flutter pub run build_runner build --delete-conflicting-outputs --define "flutter_platform_code_demo:platform_builder=platform=desktop"
  • mobile:
flutter pub run build_runner build --delete-conflicting-outputs --define "flutter_platform_code_demo:platform_builder=platform=mobile"

注解使用说明

参考source_gen的文档和用例,需要使用注解来指定需要代码生成器处理的源码和元素。

@PlatformDetector

这是用来标记需要进行代码替换的注解标记,无需解释,放在需要处理的代码源文件的第一行即可

@PlatformSpec

这是用来标记需要替换的元素的注解,注解签名为:

PlatformSpec({
    required this.platformType,
    this.renameTo,
})

其中:

  • platformType必须指定,当与当前指定的PlatformType不一致时,生成的代码中该注解所标记的代码块将被移除;
  • renameTo为可选,当改注解标记的代码块需要保留时,如果指定了renameTo,那么根据代码块类型的不同,将进行相应的替换

增加 PlatformType 的方法

lib/builder/platform_generator.dart顶部的PlatformType枚举中增加类型:

enum PlatformType {
  mobile,
  desktop,
  // add some other platform type here
}

当前支持替换的语法元素

  • 类定义(ClassDeclaration)

  • 变量定义(VariableDeclaration)

  • 顶层变量定义(TopLevelVariableDeclaration)

  • 字段定义(FieldDeclaration)

  • import指令(ImportDirective)

  • 函数定义(FunctionDeclaration)

  • 方法定义(MethodDeclaration)

    更多语法支持可以通过在lib/builder/platform_generator.dart中增加visitXXX系列的方法覆写来实现。

举例

源代码test.dart

@PlatformDetector()
import 'package:flutter_platform_code_demo/builder/platform_generator.dart';
@PlatformSpec(platformType: PlatformType.mobile)
import 'messages/mobile.dart';
@PlatformSpec(platformType: PlatformType.desktop, renameTo: 'messages/desktop.dart')
// ignore: duplicate_import
import 'messages/mobile.dart';
import 'builder/platform_annotation.dart';

@PlatformSpec(platformType: PlatformType.mobile)
const _title = 'Flutter Demo Mobile';

@PlatformSpec(platformType: PlatformType.desktop, renameTo: '_title')
// ignore: unused_element
const _titleDesktop = 'Flutter Demo Desktop';

class A {
  @PlatformSpec(platformType: PlatformType.mobile)
  int _counter = 0;

  @PlatformSpec(platformType: PlatformType.desktop, renameTo: '_counter')
  // ignore: unused_field, prefer_final_fields
  int _counterDesktop = 9;

  @PlatformSpec(platformType: PlatformType.mobile, renameTo: '_incrementCounter')
  // ignore: unused_element
  void _incrementCounterMobile() {
    _counter++;
  }

  @PlatformSpec(platformType: PlatformType.desktop)
  void _incrementCounter() {
    _counter *= 2;
  }
}

@PlatformSpec(platformType: PlatformType.mobile)
class B {
  final name = 'mobile';
}

@PlatformSpec(platformType: PlatformType.desktop, renameTo: 'B')
class C {
  final name = 'desktop';
}

在指定PlatformTypemobile时将生成如下test.p.dart代码:

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// PlatformGenerator
// **************************************************************************

@PlatformDetector()
import 'package:flutter_platform_code_demo/builder/platform_generator.dart';
@PlatformSpec(platformType: PlatformType.mobile)
import 'messages/mobile.dart';
import 'builder/platform_annotation.dart';

const _title = 'Flutter Demo Mobile';

class A {
  @PlatformSpec(platformType: PlatformType.mobile)
  int _counter = 0;
  @PlatformSpec(
      platformType: PlatformType.mobile, renameTo: '_incrementCounter')
  void _incrementCounter() {
    _counter++;
  }
}

@PlatformSpec(platformType: PlatformType.mobile)
class B {
  final name = 'mobile';
}

在指定PlatformTypedesktop时将生成如下test.p.dart代码:

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// PlatformGenerator
// **************************************************************************

@PlatformDetector()
import 'package:flutter_platform_code_demo/builder/platform_generator.dart';
@PlatformSpec(
    platformType: PlatformType.desktop, renameTo: 'messages/desktop.dart')
import 'messages/desktop.dart';
import 'builder/platform_annotation.dart';

const _title = 'Flutter Demo Desktop';

class A {
  @PlatformSpec(platformType: PlatformType.desktop, renameTo: '_counter')
  int _counter = 9;
  @PlatformSpec(platformType: PlatformType.desktop)
  void _incrementCounter() {
    _counter *= 2;
  }
}

@PlatformSpec(platformType: PlatformType.desktop, renameTo: 'B')
class B {
  final name = 'desktop';
}