diff --git a/test_flutter_message_channel/.gitignore b/test_flutter_message_channel/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..29a3a5017f048d6d8e6a450eef64435ddee44fb7 --- /dev/null +++ b/test_flutter_message_channel/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/test_flutter_message_channel/.metadata b/test_flutter_message_channel/.metadata new file mode 100644 index 0000000000000000000000000000000000000000..c3d0765d3cceaa5a4ae937d2b955a0f13d50bf3d --- /dev/null +++ b/test_flutter_message_channel/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "7f20e5d18ce4cb80c621533090a7c5113f5bdc52" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 7f20e5d18ce4cb80c621533090a7c5113f5bdc52 + base_revision: 7f20e5d18ce4cb80c621533090a7c5113f5bdc52 + - platform: android + create_revision: 7f20e5d18ce4cb80c621533090a7c5113f5bdc52 + base_revision: 7f20e5d18ce4cb80c621533090a7c5113f5bdc52 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/test_flutter_message_channel/README.md b/test_flutter_message_channel/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e8c6021644256e41200c85d7f345fa44da963f78 --- /dev/null +++ b/test_flutter_message_channel/README.md @@ -0,0 +1,19 @@ +# test_flutter_message_channel + +## 测试 Flutter 读写原生对象时间消耗 + +- 读取测试 + +1. 在 原生 层创建一个联系人列表,每项有2个字段,类型为 string +2. 从 flutter 层发送消息到原生层,原生层将数据列表序列化为字符串,然后返回 +3. 在 flutter 层将字符串还原为 dart 数据结构 +4. 循环操作 1000 次并记录总耗时 + + +- 读取并写回原生层 + +1. 在 原生 层创建一个联系人列表,每项有2个字段,类型为 string +2. 从 flutter 层发送消息到原生层,原生层将数据列表序列化为字符串,然后返回 +3. 在 flutter 层将字符串还原为 dart 数据结构, 然后在序列化为字符串发送到原生层 +4. 在 原生 层将字符串还原为对应的数据结构 +5. 循环操作 1000 次并记录总耗时 diff --git a/test_flutter_message_channel/analysis_options.yaml b/test_flutter_message_channel/analysis_options.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0d2902135caece481a035652d88970c80e29cc7e --- /dev/null +++ b/test_flutter_message_channel/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/test_flutter_message_channel/android/.gitignore b/test_flutter_message_channel/android/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6f568019d3c69d4966bb5a0f759980a1472afc1e --- /dev/null +++ b/test_flutter_message_channel/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/test_flutter_message_channel/android/app/build.gradle b/test_flutter_message_channel/android/app/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..22d4a71be7f931baddcdfe99e45c2da2359186e5 --- /dev/null +++ b/test_flutter_message_channel/android/app/build.gradle @@ -0,0 +1,73 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.test_flutter_message_channel" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.test_flutter_message_channel" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + + ndk { + abiFilters 'arm64-v8a' + } + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' +} diff --git a/test_flutter_message_channel/android/app/src/debug/AndroidManifest.xml b/test_flutter_message_channel/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..399f6981d5d35475eb18e6068ae67cdd7c731978 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/test_flutter_message_channel/android/app/src/main/AndroidManifest.xml b/test_flutter_message_channel/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..702f40583d737e4d8171f0e4fe970c662428baf4 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/test_flutter_message_channel/android/app/src/main/kotlin/com/example/test_flutter_message_channel/MainActivity.kt b/test_flutter_message_channel/android/app/src/main/kotlin/com/example/test_flutter_message_channel/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..155c35cb87cec418e1b53da2057e0be81082ab21 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/kotlin/com/example/test_flutter_message_channel/MainActivity.kt @@ -0,0 +1,81 @@ +package com.example.test_flutter_message_channel + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorManager +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.google.gson.annotations.SerializedName +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.* +import java.io.InputStream +import java.nio.ByteBuffer +import kotlin.math.log + +class MainActivity: FlutterActivity() { + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + // 0.1k + var contactModel100 = ContactModel() + // 1k + var contactModel1000 = ContactModel() + + for (i in 1..3) { + contactModel100.add(ContactDetails("name", "phone")); + } + + for (i in 1..32) { + contactModel1000.add(ContactDetails("name", "phone")); + } + + MethodChannel(flutterEngine.dartExecutor, "methodChannelDemo") + .setMethodCallHandler { call, result -> + when (call.method) { + "setContacts100" -> { + val contacts: String? = call.argument("contacts"); + // println(contacts!!.length.toString()); + contactModel100.fromJson(contacts!!); + result.success(1); + } + "setContacts1000" -> { + val contacts: String? = call.argument("contacts"); + // println(contacts.length); // 1025 + contactModel1000.fromJson(contacts!!); + result.success(1); + } + else -> result.notImplemented() + } + } + + BasicMessageChannel(flutterEngine.dartExecutor, "jsonMessageCodecDemo", JSONMessageCodec.INSTANCE) + .setMessageHandler { message, reply -> + if (message == "getContact100") { + reply.reply(contactModel100.toJson()) + } else if (message == "getContact1000") { + reply.reply(contactModel1000.toJson()) + } else { + reply.reply(null) + } + } + } +} + +open class ContactDetails(@SerializedName("name") open var name: String, @SerializedName("phone") open var phone: String) {} + +open class ContactModel { + open var contacts: MutableCollection = mutableListOf(); + + private val gson = Gson(); + + open fun add(contact: ContactDetails) { + contacts.add(contact); + } + + fun fromJson(jsonString: String) { + contacts = gson.fromJson(jsonString, object : TypeToken>() {}.type); + } + + fun toJson() : String { + return gson.toJson(mapOf("contacts" to contacts)); + } +} diff --git a/test_flutter_message_channel/android/app/src/main/res/drawable-v21/launch_background.xml b/test_flutter_message_channel/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..f74085f3f6a2b995f8ad1f9ff7b2c46dc118a9e0 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/test_flutter_message_channel/android/app/src/main/res/drawable/launch_background.xml b/test_flutter_message_channel/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..304732f8842013497e14bd02f67a55f2614fb8f7 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/test_flutter_message_channel/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test_flutter_message_channel/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 Binary files /dev/null and b/test_flutter_message_channel/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/test_flutter_message_channel/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test_flutter_message_channel/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be Binary files /dev/null and b/test_flutter_message_channel/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/test_flutter_message_channel/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test_flutter_message_channel/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..09d4391482be68e9e4a07fab769b5de337d16eb1 Binary files /dev/null and b/test_flutter_message_channel/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/test_flutter_message_channel/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test_flutter_message_channel/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c Binary files /dev/null and b/test_flutter_message_channel/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/test_flutter_message_channel/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test_flutter_message_channel/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 Binary files /dev/null and b/test_flutter_message_channel/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/test_flutter_message_channel/android/app/src/main/res/values-night/styles.xml b/test_flutter_message_channel/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..06952be745f9fa6fa75196e830d9578eb2ee631d --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/test_flutter_message_channel/android/app/src/main/res/values/styles.xml b/test_flutter_message_channel/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..cb1ef88056edd1caf99a935e434e7ff6943a0ef6 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/test_flutter_message_channel/android/app/src/profile/AndroidManifest.xml b/test_flutter_message_channel/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..399f6981d5d35475eb18e6068ae67cdd7c731978 --- /dev/null +++ b/test_flutter_message_channel/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/test_flutter_message_channel/android/build.gradle b/test_flutter_message_channel/android/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..e83fb5daca3e3c5cb366428e16d6ddbd33f81997 --- /dev/null +++ b/test_flutter_message_channel/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/test_flutter_message_channel/android/gradle.properties b/test_flutter_message_channel/android/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..598d13fee446372f156ecc38527b54c7cdcc8e3b --- /dev/null +++ b/test_flutter_message_channel/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/test_flutter_message_channel/android/gradle/wrapper/gradle-wrapper.properties b/test_flutter_message_channel/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..3c472b99c6f3501ff93513bcdf39dabe4f236a55 --- /dev/null +++ b/test_flutter_message_channel/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/test_flutter_message_channel/android/settings.gradle b/test_flutter_message_channel/android/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..7cd7128551bb8e1c5cdf8bdade409ae795e3aef9 --- /dev/null +++ b/test_flutter_message_channel/android/settings.gradle @@ -0,0 +1,29 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + + plugins { + id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false +} + +include ":app" diff --git a/test_flutter_message_channel/lib/main.dart b/test_flutter_message_channel/lib/main.dart new file mode 100644 index 0000000000000000000000000000000000000000..594472b0413e12e3a2e8b2c336ae0015256cdf7a --- /dev/null +++ b/test_flutter_message_channel/lib/main.dart @@ -0,0 +1,270 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'test flutter message channel', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: const ContactPage(), + ); + } +} + +class ContactDetails { + ContactDetails({ + required this.name, + required this.phone, + }); + + final String name; + final String phone; + + factory ContactDetails.fromMap(Map map) => ContactDetails( + name: map['name'] as String, + phone: map['phone'] as String, + ); + + Map toJson() => { + 'name': name, + 'phone': phone, + }; +} + +class ContactListModel { + ContactListModel({ + required this.contactList, + }); + + final List contactList; + + factory ContactListModel.fromJson(String jsonString) { + final jsonData = json.decode(jsonString) as Map; + return ContactListModel( + contactList: List.from((jsonData['contacts'] as List).map( + (dynamic contactDetailsMap) => ContactDetails.fromMap( + contactDetailsMap as Map, + ), + )), + ); + } + + String toJson() { + String json = jsonEncode(contactList.map((i) => i.toJson()).toList()).toString(); + return json; + } +} + +class ContactsMessageChannel { + static const MethodChannel _methodChannel = MethodChannel('methodChannelDemo'); + + static const _jsonMessageCodecChannel = + BasicMessageChannel('jsonMessageCodecDemo', JSONMessageCodec()); + + static void addContactDetails(ContactDetails contactDetails) { + _jsonMessageCodecChannel.send(contactDetails.toJson()); + } + + static Future getContacts(String type) async { + final reply = await _jsonMessageCodecChannel.send('getContact$type'); + if (reply == null) { + throw PlatformException( + code: 'INVALID', + message: 'Failed to get contact', + details: null, + ); + } else { + return ContactListModel.fromJson(reply); + } + } + + static Future setContacts(json, String type) async { + final result = await _methodChannel .invokeMethod('setContacts$type', {'contacts': json}); + return result!; + } +} + +class ContactPage extends StatefulWidget { + const ContactPage({super.key}); + + @override + State createState() => _ContactPageState(); +} + +class _ContactPageState extends State { + static const int invokeCount = 1000; + + ContactListModel contactListModel = ContactListModel(contactList: []); + + String dataType = '1000'; + String dataTypeText = '1'; + + int getCount = 0; + int getSetCount = 0; + final List timeList = []; + + _setDataType() async { + setState(() { + if (dataType == '1000') { + dataType = '100'; + dataTypeText = '0.1'; + } else { + dataType = '1000'; + dataTypeText = '1'; + } + //dataTypeText = (dataType / 1000).toString(); + }); + } + + Future _getContactData() async { + // 记录开始时间 + var startDateTime = DateTime.now(); + + // 循环调用 1000 次 + for (int i = 0; i < invokeCount; i++) { + contactListModel = await ContactsMessageChannel.getContacts(dataType); + } + + // 记录结束时间 + var endDateTime = DateTime.now(); + // 计算消耗的毫秒数 + var totalMilliseconds = endDateTime + .difference(startDateTime) + .inMilliseconds; + + getCount++; + + timeList.add("第 $getCount 次读取总耗时=$totalMilliseconds 毫秒"); + + // 更新界面 + setState(() {}); + } + + Future _getSetContactData() async { + // 记录开始时间 + var startDateTime = DateTime.now(); + + // 先从Java层读取 1KB 联系人,然后序列为JSON后在Java层还原 + for (int i = 0; i < invokeCount; i++) { + contactListModel = await ContactsMessageChannel.getContacts(dataType); + await ContactsMessageChannel.setContacts(contactListModel.toJson(), dataType); + } + + // 记录结束时间 + var endDateTime = DateTime.now(); + // 计算消耗的毫秒数 + var totalMilliseconds = endDateTime + .difference(startDateTime) + .inMilliseconds; + + getSetCount++; + + timeList.add("第 $getSetCount 次读取+写入总耗时=$totalMilliseconds 毫秒"); + + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme + .of(context) + .colorScheme + .inversePrimary, + title: const Text('test flutter message channel'), + ), + body: Flex( + direction: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 1, + child: BuildTimeListWidget(timeList), + ), + Flexible( + flex: 1, + child: contactListModel.contactList.isEmpty + ? const Center(child: Text('no data')) + : BuildContactListWidget(contactListModel.contactList), + ), + Flexible( + flex: 1, + child: ListView( + children: [ + Container(height: 10), + GestureDetector( + behavior: HitTestBehavior.opaque, + child: Text('数据长度约 $dataTypeText KB'), + onTap: () { + _setDataType(); + }, + ), + Container(height: 10), + const Text('循环执行 1000 次'), + Container(height: 15), + ElevatedButton(onPressed: _getContactData, + child: const Text('读取原生对象数据'), + ), + ElevatedButton(onPressed: _getSetContactData, + child: const Text('读取并写回原生对象'), + ), + ], + ), + ), + ], + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} + +class BuildContactListWidget extends StatelessWidget { + final List contactList; + + const BuildContactListWidget(this.contactList, {super.key}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + padding: const EdgeInsets.all(1), + itemCount: contactList.length, + itemBuilder: (context, index) { + return ListTile( + title: Text(contactList[index].name, style: const TextStyle(fontSize: 12),), + subtitle: Text(contactList[index].phone, style: const TextStyle(fontSize: 12),), + ); + }, + ); + } +} + +class BuildTimeListWidget extends StatelessWidget { + final List timeList; + + const BuildTimeListWidget(this.timeList, {super.key}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + padding: const EdgeInsets.all(2), + itemCount: timeList.length, + itemBuilder: (context, index) { + return ListTile( + title: Text(style: const TextStyle(fontSize: 12), timeList[index]) + ); + }, + ); + } +} diff --git a/test_flutter_message_channel/pubspec.lock b/test_flutter_message_channel/pubspec.lock new file mode 100644 index 0000000000000000000000000000000000000000..9f186497e11ee1416e9c5de1dfee1c6610177f5e --- /dev/null +++ b/test_flutter_message_channel/pubspec.lock @@ -0,0 +1,188 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.18.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.6" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.0" +sdks: + dart: ">=3.2.1 <4.0.0" diff --git a/test_flutter_message_channel/pubspec.yaml b/test_flutter_message_channel/pubspec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2bf61d67a917ea7eb19705780c26d93ed63301d3 --- /dev/null +++ b/test_flutter_message_channel/pubspec.yaml @@ -0,0 +1,90 @@ +name: test_flutter_message_channel +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.2.1 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test_flutter_message_channel/test/widget_test.dart b/test_flutter_message_channel/test/widget_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..9f15d5b2fa83febd1afff2964b6cbd1f30d94041 --- /dev/null +++ b/test_flutter_message_channel/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:test_flutter_message_channel/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/test_flutter_message_channel/test_flutter_message_channel.arm64.apk b/test_flutter_message_channel/test_flutter_message_channel.arm64.apk new file mode 100644 index 0000000000000000000000000000000000000000..fadea573540bb38d143c2c2c644cc982df93d314 Binary files /dev/null and b/test_flutter_message_channel/test_flutter_message_channel.arm64.apk differ