├── LICENSE ├── ios ├── Assets │ └── .gitkeep ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcworkspace │ └── contents.xcworkspacedata ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Classes │ ├── NativePlugin.h │ ├── SwiftNativePlugin.swift │ └── NativePlugin.m ├── .gitignore └── rescore.podspec ├── android ├── .gitignore ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── duet │ │ │ │ │ └── rescore │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .idea │ ├── modules.xml │ ├── misc.xml │ ├── gradle.xml │ ├── workspace.xml │ └── codeStyles │ │ └── Project.xml ├── gradle.properties ├── src │ └── main │ │ └── AndroidManifest.xml ├── settings.gradle ├── build.gradle ├── android.iml └── rescore_android.iml ├── lib ├── protos │ ├── pubspec.yaml │ ├── lib │ │ ├── src │ │ │ ├── greeting.pbenum.dart │ │ │ ├── greeting.pbjson.dart │ │ │ ├── greeting.pbgrpc.dart │ │ │ └── greeting.pb.dart │ │ └── protos.dart │ ├── .packages │ ├── pubspec.lock │ └── .dart_tool │ │ └── package_config.json ├── main.dart ├── option.dart ├── grpc.dart ├── services.dart └── bridge.dart ├── analysis_options.yaml ├── native ├── cbindgen.toml ├── src │ ├── protos │ │ ├── mod.rs │ │ └── greeting.rs │ └── lib.rs ├── Cargo.toml └── Cargo.lock ├── pubspec.yaml ├── protos └── greeting.proto ├── rescore.iml ├── README.md ├── makefile └── pubspec.lock /LICENSE: -------------------------------------------------------------------------------- 1 | MIT 2 | -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajrcarey/dart-rust-minimal-ffi-grpc-example/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/protos/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: shared_ffi_protos 2 | description: Auto-generated protobuf messages shared across FFI 3 | version: 1.0.0 4 | environment: 5 | sdk: '>=2.8.0 <3.0.0' 6 | dependencies: 7 | protobuf: ^1.0.1 8 | grpc: ^2.2.0 9 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | enable-experiment: 3 | - extension-methods 4 | # - non-nullable # Supported in dart 2.8 but not in flutter 1.17, which is still on dart 2.7 5 | # Enable in flutter once flutter ships dart 2.8 6 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 6 | -------------------------------------------------------------------------------- /lib/protos/lib/src/greeting.pbenum.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: greeting.proto 4 | // 5 | // @dart = 2.3 6 | // ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type 7 | 8 | -------------------------------------------------------------------------------- /native/cbindgen.toml: -------------------------------------------------------------------------------- 1 | language = "C" 2 | autogen_warning = "// NOTE: Append the lines below to ios/Classes/Plugin.h" 3 | #namespace = "ffi" 4 | #include_guard = "CBINDGEN_BINDINGS_H" 5 | 6 | [defines] 7 | "target_os = ios" = "TARGET_OS_IOS" 8 | "target_os = macos" = "TARGET_OS_MACOS" -------------------------------------------------------------------------------- /android/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /native/src/protos/mod.rs: -------------------------------------------------------------------------------- 1 | // Auto-generated by makefile. Do not edit by hand. 2 | pub mod greeting; 3 | 4 | use num_derive::FromPrimitive; 5 | 6 | #[derive(FromPrimitive)] 7 | pub enum MessageType { 8 | UnrecognizedMessage = -1, 9 | HelloRequest = 0, 10 | HelloResponse = 1, 11 | } 12 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | # As per note at https://flutter.dev/docs/deployment/android 6 | # https://issuetracker.google.com/issues/147096055 7 | android.bundle.enableUncompressedNativeLibs=false 8 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: minimal_ffi_grpc_example 2 | description: Minimal FFI GRPC Example 3 | version: 0.0.1 4 | 5 | environment: 6 | sdk: ">=2.8.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | cupertino_icons: ^0.1.2 12 | ffi: ^0.1.3 13 | ffi_helper: ^1.4.0 14 | protobuf: ^1.0.1 15 | grpc: ^2.2.0 16 | shared_ffi_protos: 17 | path: lib/protos 18 | 19 | dev_dependencies: 20 | build_runner: any 21 | 22 | flutter: 23 | uses-material-design: true 24 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/duet/rescore/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.duet.rescore 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /native/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "native" 3 | version = "0.0.1" 4 | authors = ["Alastair Carey "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "native" 9 | crate-type = ["staticlib", "cdylib"] 10 | 11 | [dependencies] 12 | bytes = "0.5.4" 13 | protobuf = { version = "2.14.0", features = ["with-bytes"] } 14 | num-traits = "0.2.12" 15 | num-derive = "0.3.0" 16 | log = "0.4.8" 17 | env_logger = "0.7.1" 18 | 19 | [target.'cfg(target_os="android")'.dependencies] 20 | android_logger = "0.8.6" 21 | -------------------------------------------------------------------------------- /ios/Classes/NativePlugin.h: -------------------------------------------------------------------------------- 1 | // NOTE: Append the lines below to ios/Classes/Plugin.h 2 | 3 | void initialize_ffi(void); 4 | 5 | void receive_from_ffi(int32_t request_message_type, 6 | int32_t request_message_id, 7 | const uint8_t *payload_buffer, 8 | uintptr_t payload_buffer_length, 9 | int32_t expected_response_message_type, 10 | void (*response_callback_fn)(int32_t, int32_t, const uint8_t*, uintptr_t, uint8_t)); 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Classes/SwiftNativePlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | public class SwiftNativePlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | // We are not using Flutter channels here 7 | } 8 | 9 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 10 | // Noop 11 | result(nil) 12 | } 13 | 14 | public func dummyMethodToEnforceBundling() { 15 | // dummy calls to prevent tree shaking 16 | rust_greeting(""); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Classes/NativePlugin.m: -------------------------------------------------------------------------------- 1 | #import "NativePlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "native-Swift.h" 9 | #endif 10 | 11 | @implementation NativePlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftNativePlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /android/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /lib/protos/lib/src/greeting.pbjson.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: greeting.proto 4 | // 5 | // @dart = 2.3 6 | // ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type 7 | 8 | const HelloRequest$json = const { 9 | '1': 'HelloRequest', 10 | '2': const [ 11 | const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, 12 | ], 13 | }; 14 | 15 | const HelloResponse$json = const { 16 | '1': 'HelloResponse', 17 | '2': const [ 18 | const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'}, 19 | ], 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /protos/greeting.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package com.google.greeting; 4 | 5 | // https://grpc.io/docs/languages/dart/quickstart/ 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloResponse); 11 | // Sends another greeting 12 | rpc SayHelloAgain (HelloRequest) returns (HelloResponse); 13 | } 14 | 15 | // The request message containing the user's name. 16 | message HelloRequest { 17 | string name = 1; 18 | } 19 | 20 | // The response message containing the greetings 21 | message HelloResponse { 22 | string message = 1; 23 | } 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | rootProject.allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/protos/lib/protos.dart: -------------------------------------------------------------------------------- 1 | // Auto-generated by makefile. Do not edit by hand. 2 | library shared_ffi_protos; 3 | 4 | import 'package:protobuf/protobuf.dart' as protobuf; 5 | import 'src/greeting.pb.dart'; 6 | export 'src/greeting.pb.dart'; 7 | export 'src/greeting.pbgrpc.dart'; 8 | 9 | void createServiceIndexEntries( 10 | void processOnePackage( 11 | String package, 12 | String messages, 13 | List types, 14 | List builders, 15 | String rpcs)) { 16 | processOnePackage("com.google.greeting", """HelloRequest HelloResponse """, [ 17 | MessageType.HelloRequest, 18 | MessageType.HelloResponse, 19 | ], [ 20 | () => new HelloRequest(), 21 | () => new HelloResponse(), 22 | ], """//:service Greeter {//:rpc SayHello (HelloRequest) returns (HelloResponse); //:rpc SayHelloAgain (HelloRequest) returns (HelloResponse); }"""); 23 | } 24 | 25 | enum MessageType { 26 | HelloRequest, 27 | HelloResponse, 28 | } 29 | -------------------------------------------------------------------------------- /ios/rescore.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint rescore.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'rescore' 7 | s.version = '0.0.1' 8 | s.summary = 'Duet Rescore Library Implementation' 9 | s.description = <<-DESC 10 | Duet Rescore Library Implementation 11 | DESC 12 | s.homepage = 'http://www.rescore.app' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Alastair Carey' => 'alastair@alastaircarey.com' } 15 | s.source = { :path => '.' } 16 | s.public_header_files = 'Classes**/*.h' 17 | s.source_files = 'Classes/**/*' 18 | s.static_framework = true 19 | s.vendored_libraries = "**/*.a" 20 | s.dependency 'Flutter' 21 | s.platform = :ios, '8.0' 22 | 23 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. 24 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } 25 | s.swift_version = '5.0' 26 | end 27 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | library app; 2 | 3 | import 'dart:async'; 4 | import 'dart:ffi'; 5 | import 'dart:io'; 6 | import 'dart:typed_data'; 7 | 8 | import 'package:ffi_helper/ffi_helper.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:grpc/grpc.dart'; 11 | import 'package:grpc/grpc_connection_interface.dart'; 12 | import 'package:protobuf/protobuf.dart'; 13 | import 'package:shared_ffi_protos/protos.dart'; 14 | 15 | part 'bridge.dart'; 16 | part 'grpc.dart'; 17 | part 'option.dart'; 18 | part 'services.dart'; 19 | 20 | void main() async { 21 | final HelloResponse response = await GreeterClient( 22 | // Normally a GRPC client is constructed using an HTTP2 channel. 23 | // Here, however, we supply a channel provided by our FFI 24 | // implementation. The GRPC client is unaware of any difference. 25 | NativeFFIBridge().rpcClientChannel) 26 | .sayHello(HelloRequest()..name = "Phred"); 27 | 28 | runApp(App(response.message)); 29 | } 30 | 31 | class App extends StatelessWidget { 32 | final String title = 'Hello from Rust'; 33 | 34 | final String greeting; 35 | 36 | App(this.greeting); 37 | 38 | Widget build(context) => MaterialApp( 39 | title: title, 40 | home: Scaffold( 41 | appBar: AppBar(title: Text(title)), 42 | body: Center( 43 | child: 44 | Column(mainAxisAlignment: MainAxisAlignment.center, children: [ 45 | Text(greeting), 46 | ])), 47 | )); 48 | } 49 | -------------------------------------------------------------------------------- /android/rescore_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | rescore 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/protos/.packages: -------------------------------------------------------------------------------- 1 | # Generated by pub on 2020-06-19 12:04:25.322634. 2 | async:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/async-2.4.1/lib/ 3 | charcode:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.3/lib/ 4 | collection:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/ 5 | convert:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib/ 6 | crypto:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.5/lib/ 7 | fixnum:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/fixnum-0.10.11/lib/ 8 | googleapis_auth:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/googleapis_auth-0.2.12/lib/ 9 | grpc:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/grpc-2.2.0/lib/ 10 | http:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http-0.12.1/lib/ 11 | http2:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http2-1.0.0/lib/ 12 | http_parser:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.4/lib/ 13 | meta:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/meta-1.1.8/lib/ 14 | path:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/path-1.7.0/lib/ 15 | pedantic:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/pedantic-1.9.0/lib/ 16 | protobuf:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/protobuf-1.0.1/lib/ 17 | source_span:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/source_span-1.7.0/lib/ 18 | string_scanner:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5/lib/ 19 | term_glyph:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib/ 20 | typed_data:file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.6/lib/ 21 | shared_ffi_protos:lib/ 22 | -------------------------------------------------------------------------------- /android/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 1584987421354 46 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 29 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.duet.rescore" 42 | minSdkVersion 23 43 | targetSdkVersion 29 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'androidx.test:runner:1.1.1' 66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 67 | } 68 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/option.dart: -------------------------------------------------------------------------------- 1 | part of app; 2 | 3 | class Option { 4 | Option.some(final T value) : _value = value { 5 | if (value == null) { 6 | throw _e; 7 | } 8 | } 9 | 10 | Option.none() : _value = null; 11 | 12 | factory Option.maybe( 13 | final T // TODO: T? once Flutter supports dart 2.8 14 | value) => 15 | value == null ? new Option.none() : new Option.some(value); 16 | 17 | final T _value; 18 | 19 | bool get isEmpty => _value == null; 20 | 21 | bool get isNotEmpty => _value != null; 22 | 23 | bool contains(final T that) => isNotEmpty && _value == that; 24 | 25 | Iterable toIterable() => isNotEmpty ? [_value] : []; 26 | 27 | void ifMissing(void f()) { 28 | if (isEmpty) { 29 | f(); 30 | } 31 | } 32 | 33 | void ifPresent(void f(final T t)) { 34 | if (isNotEmpty) { 35 | f(_value); 36 | } 37 | } 38 | 39 | void ifContains(final T that, void f()) { 40 | if (contains(that)) { 41 | f(); 42 | } 43 | } 44 | 45 | void match(void ifPresent(final T v), void ifMissing()) => 46 | isNotEmpty ? ifPresent(_value) : ifMissing(); 47 | 48 | R cond(R ifPresent(final T t), R ifMissing()) => 49 | isEmpty ? ifMissing() : ifPresent(_value); 50 | 51 | bool filter(bool predicate(final T v)) => isEmpty ? false : predicate(_value); 52 | 53 | Option map(R mapping(final T v)) => 54 | isEmpty ? new Option.none() : new Option.maybe(mapping(_value)); 55 | 56 | Option flatMap(Option mapping(final T v)) => 57 | isEmpty ? new Option.none() : mapping(_value); 58 | 59 | T orElse(final T sentinel) => isEmpty ? sentinel : _value; 60 | 61 | T orElseGet(T supplier()) => isEmpty ? supplier() : _value; 62 | 63 | Option orElsePass(covariant Option supplier()) => 64 | isEmpty ? supplier() : this; 65 | 66 | T orElseThrow(final Exception e) => isEmpty ? throw e : _value; 67 | 68 | T orElsePanic() => orElseThrow(_e); 69 | 70 | static final NullArgumentException _e = new NullArgumentException(); 71 | 72 | @override 73 | bool operator ==(Object other) { 74 | if (!(other is Option)) { 75 | return false; 76 | } else { 77 | return _value == (other as Option)._value; 78 | } 79 | } 80 | 81 | @override 82 | String toString() => isNotEmpty ? 'Some<$T = $_value>' : 'None<$T>'; 83 | } 84 | 85 | class NullArgumentException implements Exception {} 86 | 87 | // ignore: non_constant_identifier_names 88 | Option Some(final T value) => Option.some(value); 89 | 90 | // ignore: non_constant_identifier_names 91 | Option None() => Option.none(); 92 | 93 | // ignore: non_constant_identifier_names 94 | Option Maybe( 95 | final T // TODO: T? once Flutter supports dart 2.8 96 | value) => 97 | Option.maybe(value); 98 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/protos/lib/src/greeting.pbgrpc.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: greeting.proto 4 | // 5 | // @dart = 2.3 6 | // ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type 7 | 8 | import 'dart:async' as $async; 9 | 10 | import 'dart:core' as $core; 11 | 12 | import 'package:grpc/service_api.dart' as $grpc; 13 | import 'greeting.pb.dart' as $0; 14 | export 'greeting.pb.dart'; 15 | 16 | class GreeterClient extends $grpc.Client { 17 | static final _$sayHello = 18 | $grpc.ClientMethod<$0.HelloRequest, $0.HelloResponse>( 19 | '/com.google.greeting.Greeter/SayHello', 20 | ($0.HelloRequest value) => value.writeToBuffer(), 21 | ($core.List<$core.int> value) => $0.HelloResponse.fromBuffer(value)); 22 | static final _$sayHelloAgain = 23 | $grpc.ClientMethod<$0.HelloRequest, $0.HelloResponse>( 24 | '/com.google.greeting.Greeter/SayHelloAgain', 25 | ($0.HelloRequest value) => value.writeToBuffer(), 26 | ($core.List<$core.int> value) => $0.HelloResponse.fromBuffer(value)); 27 | 28 | GreeterClient($grpc.ClientChannel channel, {$grpc.CallOptions options}) 29 | : super(channel, options: options); 30 | 31 | $grpc.ResponseFuture<$0.HelloResponse> sayHello($0.HelloRequest request, 32 | {$grpc.CallOptions options}) { 33 | final call = $createCall(_$sayHello, $async.Stream.fromIterable([request]), 34 | options: options); 35 | return $grpc.ResponseFuture(call); 36 | } 37 | 38 | $grpc.ResponseFuture<$0.HelloResponse> sayHelloAgain($0.HelloRequest request, 39 | {$grpc.CallOptions options}) { 40 | final call = $createCall( 41 | _$sayHelloAgain, $async.Stream.fromIterable([request]), 42 | options: options); 43 | return $grpc.ResponseFuture(call); 44 | } 45 | } 46 | 47 | abstract class GreeterServiceBase extends $grpc.Service { 48 | $core.String get $name => 'com.google.greeting.Greeter'; 49 | 50 | GreeterServiceBase() { 51 | $addMethod($grpc.ServiceMethod<$0.HelloRequest, $0.HelloResponse>( 52 | 'SayHello', 53 | sayHello_Pre, 54 | false, 55 | false, 56 | ($core.List<$core.int> value) => $0.HelloRequest.fromBuffer(value), 57 | ($0.HelloResponse value) => value.writeToBuffer())); 58 | $addMethod($grpc.ServiceMethod<$0.HelloRequest, $0.HelloResponse>( 59 | 'SayHelloAgain', 60 | sayHelloAgain_Pre, 61 | false, 62 | false, 63 | ($core.List<$core.int> value) => $0.HelloRequest.fromBuffer(value), 64 | ($0.HelloResponse value) => value.writeToBuffer())); 65 | } 66 | 67 | $async.Future<$0.HelloResponse> sayHello_Pre( 68 | $grpc.ServiceCall call, $async.Future<$0.HelloRequest> request) async { 69 | return sayHello(call, await request); 70 | } 71 | 72 | $async.Future<$0.HelloResponse> sayHelloAgain_Pre( 73 | $grpc.ServiceCall call, $async.Future<$0.HelloRequest> request) async { 74 | return sayHelloAgain(call, await request); 75 | } 76 | 77 | $async.Future<$0.HelloResponse> sayHello( 78 | $grpc.ServiceCall call, $0.HelloRequest request); 79 | $async.Future<$0.HelloResponse> sayHelloAgain( 80 | $grpc.ServiceCall call, $0.HelloRequest request); 81 | } 82 | -------------------------------------------------------------------------------- /lib/protos/lib/src/greeting.pb.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: greeting.proto 4 | // 5 | // @dart = 2.3 6 | // ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type 7 | 8 | import 'dart:core' as $core; 9 | 10 | import 'package:protobuf/protobuf.dart' as $pb; 11 | 12 | class HelloRequest extends $pb.GeneratedMessage { 13 | static final $pb.BuilderInfo _i = $pb.BuilderInfo('HelloRequest', package: const $pb.PackageName('com.google.greeting'), createEmptyInstance: create) 14 | ..aOS(1, 'name') 15 | ..hasRequiredFields = false 16 | ; 17 | 18 | HelloRequest._() : super(); 19 | factory HelloRequest() => create(); 20 | factory HelloRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); 21 | factory HelloRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); 22 | HelloRequest clone() => HelloRequest()..mergeFromMessage(this); 23 | HelloRequest copyWith(void Function(HelloRequest) updates) => super.copyWith((message) => updates(message as HelloRequest)); 24 | $pb.BuilderInfo get info_ => _i; 25 | @$core.pragma('dart2js:noInline') 26 | static HelloRequest create() => HelloRequest._(); 27 | HelloRequest createEmptyInstance() => create(); 28 | static $pb.PbList createRepeated() => $pb.PbList(); 29 | @$core.pragma('dart2js:noInline') 30 | static HelloRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); 31 | static HelloRequest _defaultInstance; 32 | 33 | @$pb.TagNumber(1) 34 | $core.String get name => $_getSZ(0); 35 | @$pb.TagNumber(1) 36 | set name($core.String v) { $_setString(0, v); } 37 | @$pb.TagNumber(1) 38 | $core.bool hasName() => $_has(0); 39 | @$pb.TagNumber(1) 40 | void clearName() => clearField(1); 41 | } 42 | 43 | class HelloResponse extends $pb.GeneratedMessage { 44 | static final $pb.BuilderInfo _i = $pb.BuilderInfo('HelloResponse', package: const $pb.PackageName('com.google.greeting'), createEmptyInstance: create) 45 | ..aOS(1, 'message') 46 | ..hasRequiredFields = false 47 | ; 48 | 49 | HelloResponse._() : super(); 50 | factory HelloResponse() => create(); 51 | factory HelloResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); 52 | factory HelloResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); 53 | HelloResponse clone() => HelloResponse()..mergeFromMessage(this); 54 | HelloResponse copyWith(void Function(HelloResponse) updates) => super.copyWith((message) => updates(message as HelloResponse)); 55 | $pb.BuilderInfo get info_ => _i; 56 | @$core.pragma('dart2js:noInline') 57 | static HelloResponse create() => HelloResponse._(); 58 | HelloResponse createEmptyInstance() => create(); 59 | static $pb.PbList createRepeated() => $pb.PbList(); 60 | @$core.pragma('dart2js:noInline') 61 | static HelloResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); 62 | static HelloResponse _defaultInstance; 63 | 64 | @$pb.TagNumber(1) 65 | $core.String get message => $_getSZ(0); 66 | @$pb.TagNumber(1) 67 | set message($core.String v) { $_setString(0, v); } 68 | @$pb.TagNumber(1) 69 | $core.bool hasMessage() => $_has(0); 70 | @$pb.TagNumber(1) 71 | void clearMessage() => clearField(1); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/protos/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.4.1" 11 | charcode: 12 | dependency: transitive 13 | description: 14 | name: charcode 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.1.3" 18 | collection: 19 | dependency: transitive 20 | description: 21 | name: collection 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.14.12" 25 | convert: 26 | dependency: transitive 27 | description: 28 | name: convert 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.1.1" 32 | crypto: 33 | dependency: transitive 34 | description: 35 | name: crypto 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.5" 39 | fixnum: 40 | dependency: transitive 41 | description: 42 | name: fixnum 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.10.11" 46 | googleapis_auth: 47 | dependency: transitive 48 | description: 49 | name: googleapis_auth 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.2.12" 53 | grpc: 54 | dependency: "direct main" 55 | description: 56 | name: grpc 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.2.0" 60 | http: 61 | dependency: transitive 62 | description: 63 | name: http 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.12.1" 67 | http2: 68 | dependency: transitive 69 | description: 70 | name: http2 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.0.0" 74 | http_parser: 75 | dependency: transitive 76 | description: 77 | name: http_parser 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "3.1.4" 81 | meta: 82 | dependency: transitive 83 | description: 84 | name: meta 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.1.8" 88 | path: 89 | dependency: transitive 90 | description: 91 | name: path 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.7.0" 95 | pedantic: 96 | dependency: transitive 97 | description: 98 | name: pedantic 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.9.0" 102 | protobuf: 103 | dependency: "direct main" 104 | description: 105 | name: protobuf 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.0.1" 109 | source_span: 110 | dependency: transitive 111 | description: 112 | name: source_span 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.7.0" 116 | string_scanner: 117 | dependency: transitive 118 | description: 119 | name: string_scanner 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.0.5" 123 | term_glyph: 124 | dependency: transitive 125 | description: 126 | name: term_glyph 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.1.0" 130 | typed_data: 131 | dependency: transitive 132 | description: 133 | name: typed_data 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.1.6" 137 | sdks: 138 | dart: ">=2.8.0 <3.0.0" 139 | -------------------------------------------------------------------------------- /android/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /lib/grpc.dart: -------------------------------------------------------------------------------- 1 | part of app; 2 | 3 | class NativeFFIRPCClientChannel extends ClientChannelBase 4 | implements ClientChannel { 5 | final _connection = new NativeFFIRPCClientConnection(); 6 | 7 | @override 8 | ClientConnection createConnection() { 9 | return _connection; 10 | } 11 | 12 | @override 13 | final String host = "localhost"; 14 | 15 | @override 16 | final ChannelOptions options = 17 | new ChannelOptions(credentials: ChannelCredentials.insecure()); 18 | 19 | @override 20 | final int port = 0; 21 | } 22 | 23 | class NativeFFIRPCClientConnection implements ClientConnection { 24 | @override 25 | final String authority = "localhost"; 26 | 27 | @override 28 | void dispatchCall(ClientCall call) { 29 | call.onConnectionReady(this); 30 | } 31 | 32 | @override 33 | GrpcTransportStream makeRequest(String path, Duration timeout, 34 | Map metadata, ErrorHandler onRequestFailure) { 35 | return new NativeFFIRPCTransportStream(path); 36 | } 37 | 38 | @override 39 | final String scheme = "ffi"; 40 | 41 | @override 42 | Future shutdown() { 43 | return Future.value(null); 44 | } 45 | 46 | @override 47 | Future terminate() { 48 | return Future.value(null); 49 | } 50 | } 51 | 52 | class NativeFFIRPCTransportStream implements GrpcTransportStream { 53 | final StreamController _incomingMessages = StreamController(); 54 | 55 | Stream get incomingMessages => _incomingMessages.stream; 56 | 57 | final StreamController _outgoingMessages = StreamController(); 58 | 59 | StreamSink get outgoingMessages => _outgoingMessages.sink; 60 | 61 | final String _path; 62 | 63 | bool _areHeadersSent = false; 64 | 65 | NativeFFIRPCTransportStream(this._path) { 66 | final requestMessageType = NativeFFIBridge._serviceIndex 67 | .getRequestMessageTypeForService(_path) 68 | .flatMap(NativeFFIBridge._serviceIndex.getIntValueFromMessageType); 69 | 70 | final responseMessageType = NativeFFIBridge._serviceIndex 71 | .getResponseMessageTypeForService(_path) 72 | .flatMap(NativeFFIBridge._serviceIndex.getIntValueFromMessageType); 73 | 74 | if (requestMessageType.isNotEmpty && responseMessageType.isNotEmpty) { 75 | final requestType = requestMessageType.orElsePanic(); 76 | 77 | final expectedResponseType = responseMessageType.orElsePanic(); 78 | 79 | final int id = NativeFFIBridge._getNextMessageId(); 80 | 81 | int sequence = 0; 82 | 83 | _outgoingMessages.stream.listen((requestPayload) { 84 | NativeFFIBridge._send( 85 | requestType, id, sequence++, requestPayload, expectedResponseType, 86 | (messageType, inReplyToId, responsePayload, 87 | isResponseStreamComplete) { 88 | if (!_areHeadersSent) { 89 | _areHeadersSent = true; 90 | _incomingMessages.add(new GrpcMetadata({})); 91 | } 92 | 93 | // We need to clone the response payload buffer before adding it 94 | // to the incoming messages stream. The buffer was allocated in 95 | // native code, and it will be deallocated at the end of this 96 | // function callback, i.e. _before_ the incoming messages stream 97 | // is flushed in the next microtask. Failing to clone the payload 98 | // buffer results in failed deserialization of the payload. 99 | 100 | _incomingMessages 101 | .add(new GrpcData(responsePayload.toList(), isCompressed: false)); 102 | 103 | if (isResponseStreamComplete) { 104 | _incomingMessages.add(new GrpcMetadata({})); 105 | _incomingMessages.close(); 106 | } 107 | }); 108 | }); 109 | } 110 | } 111 | 112 | @override 113 | Future terminate() async { 114 | _outgoingMessages.close(); 115 | _incomingMessages.close(); 116 | return Future.value(null); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/protos/.dart_tool/package_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configVersion": 2, 3 | "packages": [ 4 | { 5 | "name": "async", 6 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/async-2.4.1", 7 | "packageUri": "lib/", 8 | "languageVersion": "2.2" 9 | }, 10 | { 11 | "name": "charcode", 12 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.3", 13 | "packageUri": "lib/", 14 | "languageVersion": "2.0" 15 | }, 16 | { 17 | "name": "collection", 18 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12", 19 | "packageUri": "lib/", 20 | "languageVersion": "2.0" 21 | }, 22 | { 23 | "name": "convert", 24 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1", 25 | "packageUri": "lib/", 26 | "languageVersion": "1.17" 27 | }, 28 | { 29 | "name": "crypto", 30 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.5", 31 | "packageUri": "lib/", 32 | "languageVersion": "2.3" 33 | }, 34 | { 35 | "name": "fixnum", 36 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/fixnum-0.10.11", 37 | "packageUri": "lib/", 38 | "languageVersion": "2.1" 39 | }, 40 | { 41 | "name": "googleapis_auth", 42 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/googleapis_auth-0.2.12", 43 | "packageUri": "lib/", 44 | "languageVersion": "2.0" 45 | }, 46 | { 47 | "name": "grpc", 48 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/grpc-2.2.0", 49 | "packageUri": "lib/", 50 | "languageVersion": "2.2" 51 | }, 52 | { 53 | "name": "http", 54 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http-0.12.1", 55 | "packageUri": "lib/", 56 | "languageVersion": "2.4" 57 | }, 58 | { 59 | "name": "http2", 60 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http2-1.0.0", 61 | "packageUri": "lib/", 62 | "languageVersion": "2.0" 63 | }, 64 | { 65 | "name": "http_parser", 66 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.4", 67 | "packageUri": "lib/", 68 | "languageVersion": "2.3" 69 | }, 70 | { 71 | "name": "meta", 72 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/meta-1.1.8", 73 | "packageUri": "lib/", 74 | "languageVersion": "1.12" 75 | }, 76 | { 77 | "name": "path", 78 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/path-1.7.0", 79 | "packageUri": "lib/", 80 | "languageVersion": "2.0" 81 | }, 82 | { 83 | "name": "pedantic", 84 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/pedantic-1.9.0", 85 | "packageUri": "lib/", 86 | "languageVersion": "2.1" 87 | }, 88 | { 89 | "name": "protobuf", 90 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/protobuf-1.0.1", 91 | "packageUri": "lib/", 92 | "languageVersion": "2.0" 93 | }, 94 | { 95 | "name": "source_span", 96 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/source_span-1.7.0", 97 | "packageUri": "lib/", 98 | "languageVersion": "2.6" 99 | }, 100 | { 101 | "name": "string_scanner", 102 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5", 103 | "packageUri": "lib/", 104 | "languageVersion": "2.0" 105 | }, 106 | { 107 | "name": "term_glyph", 108 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0", 109 | "packageUri": "lib/", 110 | "languageVersion": "1.8" 111 | }, 112 | { 113 | "name": "typed_data", 114 | "rootUri": "file:///home/alastair/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.6", 115 | "packageUri": "lib/", 116 | "languageVersion": "2.0" 117 | }, 118 | { 119 | "name": "shared_ffi_protos", 120 | "rootUri": "../", 121 | "packageUri": "lib/", 122 | "languageVersion": "2.8" 123 | } 124 | ], 125 | "generated": "2020-06-19T11:04:25.380407Z", 126 | "generator": "pub", 127 | "generatorVersion": "2.8.4" 128 | } 129 | -------------------------------------------------------------------------------- /native/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod protos; 2 | 3 | use log::debug; 4 | use num_traits::FromPrimitive; 5 | use protobuf::{Message, ProtobufError, ProtobufResult}; 6 | 7 | use crate::protos::greeting::*; 8 | use crate::protos::MessageType; 9 | 10 | #[cfg(target_os = "android")] 11 | use {android_logger::Config, log::Level}; 12 | 13 | #[allow(clippy::missing_safety_doc)] 14 | #[no_mangle] 15 | pub unsafe extern "C" fn initialize_ffi() { 16 | #[cfg(target_os = "android")] 17 | { 18 | android_logger::init_once(Config::default().with_min_level(Level::Debug)); 19 | } 20 | debug!("Native FFI Bridge receiver initialized."); 21 | } 22 | 23 | #[allow(clippy::missing_safety_doc)] 24 | #[no_mangle] 25 | pub unsafe extern "C" fn receive_from_ffi( 26 | request_message_type: i32, 27 | request_message_id: i32, 28 | payload_buffer: *const u8, 29 | payload_buffer_length: usize, 30 | expected_response_message_type: i32, 31 | response_callback_fn: extern "C" fn(i32, i32, *const u8, usize, u8), 32 | ) { 33 | let request_payload_buffer = 34 | &std::slice::from_raw_parts(payload_buffer, payload_buffer_length).to_vec(); 35 | 36 | let (response_message_type, response_payload, is_response_complete) = 37 | match FromPrimitive::from_i32(request_message_type) { 38 | Some(request_message_type) => { 39 | let (response_message_type, response_payload) = dispatch( 40 | request_message_type, 41 | FromPrimitive::from_i32(expected_response_message_type), 42 | request_payload_buffer, 43 | ); 44 | 45 | (response_message_type as i32, response_payload, 1) 46 | // TODO: stream responses 47 | // (accommodated by sending 0 instead of 1 as final argument to Dart callback 48 | // to indicate more payloads to come - 1 signals end of stream) 49 | } 50 | None => ( 51 | -1, 52 | ProtobufResult::Err(ProtobufError::MessageNotInitialized { 53 | message: "Unrecognized message", 54 | }), 55 | 1, 56 | ), 57 | }; 58 | 59 | if response_message_type == -1 { 60 | // Unrecognized message. 61 | 62 | response_callback_fn(-1, request_message_id, Vec::with_capacity(0).as_ptr(), 0, 1); 63 | } else if expected_response_message_type == -1 { 64 | // Caller does not expect a reply, no need to do anything. 65 | } else if response_message_type == expected_response_message_type { 66 | // Message recognized and valid response prepared; pass back to caller. 67 | 68 | // TODO: will attempt unwrap of response_payload even if it's the ProtobufResult::Err 69 | // we just set above for an unrecognized message. 70 | let response_payload_buffer = response_payload.unwrap(); 71 | 72 | response_callback_fn( 73 | response_message_type, 74 | request_message_id, 75 | response_payload_buffer.as_ptr(), 76 | response_payload_buffer.len(), 77 | is_response_complete, 78 | ); 79 | } else { 80 | // We recognized the caller's message and prepared a response, but the response 81 | // we prepared differs in type from the response the caller is expecting. 82 | 83 | response_callback_fn(-2, request_message_id, Vec::with_capacity(0).as_ptr(), 0, 1); 84 | } 85 | } 86 | 87 | pub(crate) fn dispatch( 88 | request_message_type: MessageType, 89 | expected_response_message_type: Option, 90 | request_payload_buffer: &[u8], 91 | ) -> (MessageType, ProtobufResult>) { 92 | match request_message_type { 93 | MessageType::HelloRequest => { 94 | let (response_message_type, response) = handle_hello_request_message( 95 | protobuf::parse_from_bytes(request_payload_buffer).unwrap(), 96 | ); 97 | 98 | (response_message_type, response.write_to_bytes()) 99 | } 100 | _ => unimplemented!(), 101 | } 102 | } 103 | 104 | fn handle_hello_request_message(request: HelloRequest) -> (MessageType, HelloResponse) { 105 | let mut response = HelloResponse::new(); 106 | 107 | debug!( 108 | "Rust received a message over FFI with name {}", 109 | request.get_name() 110 | ); 111 | 112 | response.set_message(format!("Hello from Rust, {}!", request.get_name())); 113 | 114 | (MessageType::HelloResponse, response) 115 | } 116 | -------------------------------------------------------------------------------- /rescore.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dart-rust-minimal-ffi-grpc-example 2 | 3 | Building on the excellent starting point provided by truongsinh in 4 | https://github.com/truongsinh/flutter-plugin-protobuf, 5 | this example demonstrates building a protocol buffers-based messaging 6 | system between Dart and a native library (built in Rust in this case) 7 | over FFI. 8 | 9 | Once procotol buffers over FFI are implemented, it is then possible to add 10 | support for GRPC, Google's RPC standard. This makes calling into native code 11 | from Dart effortless. 12 | 13 | ## Prerequisites 14 | 15 | * An existing, up-to-date installation of Dart and Flutter. 16 | * An existing, up-to-date installation of the Android SDK, and the correctly configured environment variables to go with it, in particular `$ANDROID_NDK_HOME`. 17 | * An existing, up-to-date installation of rust, rustup and cargo. 18 | * The standard GNU tools that come with any *nix distribution, including GNU `make` or an equivalent. 19 | 20 | Everything below was tested on Arch Linux. It should work without changes on any 21 | up-to-date Linux distribution, and probably on macOS as well (given a few caveats 22 | mentioned below). 23 | 24 | ## Build 25 | 26 | 1. Make sure your build environment is set up. 27 | 28 | ~~~ 29 | make init 30 | ~~~ 31 | 32 | 2. Build the native library and shared protocol buffers definitions. 33 | 34 | ~~~ 35 | make all 36 | ~~~ 37 | 38 | 3. Run the app in Flutter. 39 | 40 | ~~~ 41 | flutter run 42 | ~~~ 43 | 44 | ## What's it doing? 45 | 46 | There's a lot going on in `make all`. To break it down: 47 | 48 | 1. `make clean`: The build environment is cleaned of prior artifacts. 49 | 2. `make protos`: Source code for both Dart and Rust is generated from the protocol buffer definitions in /protos. 50 | 3. `make android-debug`: The Rust code is compiled into three separate binaries, one for each of the three Android architectures. We build debug binaries to keep build times down. 51 | 4. `make ios-debug`: The Rust code is compiled into two separate binaries, one for each of the two support iOS architectures. Note that this only takes place if you're running macOS. 52 | 5. `make bindings`: A C-style header file is derived from the Rust binaries - this is necessary for library linking when packaging an iOS build with XCode. 53 | 6. `make install`: Build artificats are copied into their appropriate positions in the Flutter /android and /ios folders, ready to be packaged with either `flutter run` or `flutter build`. 54 | 55 | That's enough talk about the build environment. Let's look at the implementation. 56 | 57 | ## What's in the code? 58 | 59 | FFI is largely driven from the Dart side. In Rust, we export two functions for 60 | Dart to discover: `initialize_ffi()`, which performs any start-up initialization required 61 | in the native code (in this example, it just sets up logcat logging for Android, 62 | nothing else), and `receive_from_ffi()`, which accepts a protocol buffer from Dart 63 | and dispatches a result. The code is in `/native/lib.rs`. 64 | 65 | There are three components to the Dart side. In `lib/bridge.dart`, we define the 66 | FFI interface that calls the two functions exported from Rust. This FFI bridge contains 67 | all the functionality necessary to send requests to, and receive responses from, 68 | the native code, although it's a bit cumbersome to use directly. To make things easier, 69 | we provide `lib/grpc.dart`, an implementation of `GrpcTransportStream` that uses 70 | our FFI bridge. This is the only substantive piece of code required to support GRPC; 71 | stub definitions for everything else are provided as part of `package:grpc`. Finally, 72 | we provide a helper library, `lib/services.dart`, that decodes the service definitions 73 | from the .proto files, since the code generation step doesn't do this for us in Dart. 74 | Without this, our GRPC implementation wouldn't know how to associate message types with services. 75 | 76 | ## The example application 77 | 78 | `lib/main.dart` demonstrates a very, very simple example. The standard `greeting.proto` 79 | used in Google's protocol buffers quickstart guide is also used here - it's located in `protos/`. 80 | It defines two messages, `HelloRequest` and `HelloResponse`, and binds those messages together into a 81 | GRPC service (`Greeter`) that provides two functions, `SayHello()` and `SayHelloAgain()`. 82 | 83 | In the Dart code in `/lib/main.dart`, we create an instance of the `GreeterClient`, 84 | we bind our FFI channel to it, and we call the `SayHello()` function to send a 85 | `HelloRequest` message to Rust. Rust returns a `HelloResponse` in return, which we then 86 | display on screen in a Flutter widget. That's it. 87 | 88 | ## TODOs 89 | 90 | * Streaming requests from Dart to native are supported, but the message sequence numbers are not actually delivered to the native code yet. 91 | * Streaming responses from native back to Dart are in progress, but not yet completed. 92 | * In a perfect world, response dispatch would be handled using async/await in Rust - everything is sync at the moment. 93 | * The `make protos` section of the makefile does a lot of text processing using awk. There's almost certainly a better way. 94 | 95 | ## More reading 96 | 97 | * Google protocol buffers and RPC services documentation: https://developers.google.com/protocol-buffers/ 98 | * Protocol buffers are usually used over HTTP2, as explained here: https://medium.com/@bettdougie/building-an-end-to-end-system-using-grpc-flutter-part-1-d23b2356ed28 99 | 100 | ## Notes 101 | 102 | * Minimum Android API level is 23 - lower than this, and the libraries created by Rust aren't correctly loaded from within the Flutter app. 103 | * While this example was built using Linux, in theory everything should work on an appropriately configured Mac as well - but you will likely need to install GNU gawk, as the vendor-supplied version of awk doesn't like the syntax used in the makefile. 104 | * It is absolutely possible to extend this process to include building the equivalent binaries and packages for iOS. An outline is provided in the makefile. 105 | 106 | -------------------------------------------------------------------------------- /lib/services.dart: -------------------------------------------------------------------------------- 1 | part of app; 2 | 3 | typedef T Supplier(); 4 | 5 | class ProtobufServiceIndex { 6 | Map _messageTypesByIntValue = new Map(); 7 | 8 | Map _intValuesByMessageType = new Map(); 9 | 10 | Map _messageTypesByQualifiedMessageName = 11 | new Map(); 12 | 13 | Map> _buildersByMessageType = 14 | new Map>(); 15 | 16 | Map _messageTypesByClassName = 17 | new Map(); 18 | 19 | Map _classNamesByMessageType = 20 | new Map(); 21 | 22 | Map _requestMessageTypesByQualifiedServiceName = 23 | new Map(); 24 | 25 | Map _responseMessageTypesByQualifiedServiceName = 26 | new Map(); 27 | 28 | Map _requestIsStreamByQualifiedServiceName = 29 | new Map(); 30 | 31 | Map _responseIsStreamByQualifiedServiceName = 32 | new Map(); 33 | 34 | ProtobufServiceIndex() { 35 | createServiceIndexEntries(this._createServiceIndexEntriesForOnePackage); 36 | } 37 | 38 | void _createServiceIndexEntriesForOnePackage( 39 | final String packageName, 40 | final String messageNamesInPackage, 41 | final List messageTypesInPackage, 42 | final List> messageBuildersInPackage, 43 | final String rpcServicesInPackage) { 44 | int index = 0; 45 | 46 | messageTypesInPackage.forEach((MessageType type) { 47 | final int sequence = _messageTypesByIntValue.length; 48 | 49 | _messageTypesByIntValue[sequence] = type; 50 | _intValuesByMessageType[type] = sequence; 51 | 52 | Maybe(messageBuildersInPackage[index]) 53 | .ifPresent((Supplier builder) { 54 | _buildersByMessageType[type] = builder; 55 | 56 | final built = builder(); 57 | 58 | _messageTypesByClassName[built.runtimeType.toString()] = type; 59 | _classNamesByMessageType[type] = built.runtimeType.toString(); 60 | }); 61 | 62 | index++; 63 | }); 64 | 65 | index = 0; 66 | 67 | messageNamesInPackage.trim().split(" ").forEach((String messageName) { 68 | Maybe(messageTypesInPackage[index]).ifPresent((MessageType type) => 69 | _messageTypesByQualifiedMessageName[ 70 | packageName + '.' + messageName.trim()] = type); 71 | 72 | index++; 73 | }); 74 | 75 | rpcServicesInPackage.split('//:service ').forEach((service) { 76 | if (service.trim().isNotEmpty) { 77 | final String serviceName = service.split(' {')[0].trim(); 78 | 79 | index = 0; 80 | 81 | service.split('//:rpc ').forEach((String rpc) { 82 | if (index > 0) { 83 | final List fields = rpc.split('('); 84 | 85 | final rpcName = fields[0].trim(); 86 | 87 | final qualifiedServiceName = 88 | '/' + packageName + '.' + serviceName + '/' + rpcName; 89 | 90 | String requestMessageName = 91 | fields[1].substring(0, fields[1].lastIndexOf(')')).trim(); 92 | 93 | if (requestMessageName.startsWith('stream ')) { 94 | requestMessageName = 95 | requestMessageName.substring('stream '.length); 96 | 97 | _requestIsStreamByQualifiedServiceName[qualifiedServiceName] = 98 | true; 99 | } else { 100 | _requestIsStreamByQualifiedServiceName[qualifiedServiceName] = 101 | false; 102 | } 103 | 104 | Maybe(_messageTypesByQualifiedMessageName[ 105 | packageName + '.' + requestMessageName]) 106 | .ifPresent((type) => _requestMessageTypesByQualifiedServiceName[ 107 | qualifiedServiceName] = type); 108 | 109 | String responseMessageName = 110 | fields[2].substring(0, fields[2].lastIndexOf(')')).trim(); 111 | 112 | if (responseMessageName.startsWith('stream ')) { 113 | responseMessageName = 114 | responseMessageName.substring('stream '.length); 115 | 116 | _responseIsStreamByQualifiedServiceName[qualifiedServiceName] = 117 | true; 118 | } else { 119 | _responseIsStreamByQualifiedServiceName[qualifiedServiceName] = 120 | false; 121 | } 122 | 123 | Maybe(_messageTypesByQualifiedMessageName[ 124 | packageName + '.' + responseMessageName]) 125 | .ifPresent((type) => 126 | _responseMessageTypesByQualifiedServiceName[ 127 | qualifiedServiceName] = type); 128 | } 129 | 130 | index++; 131 | }); 132 | } 133 | }); 134 | } 135 | 136 | Option getIntValueFromMessageType(MessageType type) => 137 | Maybe(_intValuesByMessageType[type]); 138 | 139 | Option getMessageTypeFromIntValue(int value) => 140 | Maybe(_messageTypesByIntValue[value]); 141 | 142 | Option getEmptyMessageFromMessageType(MessageType type) => 143 | Maybe(_buildersByMessageType[type]).map((builder) => builder()); 144 | 145 | Option getDecodedPayloadFromMessageType( 146 | MessageType type, Uint8List buffer) => 147 | getEmptyMessageFromMessageType(type) 148 | .map((message) => message..mergeFromBuffer(buffer)); 149 | 150 | Option getMessageTypeForMessage( 151 | T message) => 152 | Maybe(_messageTypesByQualifiedMessageName[ 153 | message.info_.qualifiedMessageName]); 154 | 155 | Option 156 | getMessageTypeForMessageClass() => 157 | Maybe(_messageTypesByClassName[T.toString()]); 158 | 159 | Option getRequestMessageTypeForService(String path) => 160 | Maybe(_requestMessageTypesByQualifiedServiceName[path]); 161 | 162 | Option getResponseMessageTypeForService(String path) => 163 | Maybe(_responseMessageTypesByQualifiedServiceName[path]); 164 | 165 | bool getRequestIsStreamForService(String path) => 166 | Maybe(_requestIsStreamByQualifiedServiceName[path]).orElse(false); 167 | 168 | bool getResponseIsStreamForService(String path) => 169 | Maybe(_responseIsStreamByQualifiedServiceName[path]).orElse(false); 170 | } 171 | -------------------------------------------------------------------------------- /native/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "android_log-sys" 16 | version = "0.1.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" 19 | 20 | [[package]] 21 | name = "android_logger" 22 | version = "0.8.6" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8cbd542dd180566fad88fd2729a53a62a734843c626638006a9d63ec0688484e" 25 | dependencies = [ 26 | "android_log-sys", 27 | "env_logger", 28 | "lazy_static", 29 | "log", 30 | ] 31 | 32 | [[package]] 33 | name = "atty" 34 | version = "0.2.14" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 37 | dependencies = [ 38 | "hermit-abi", 39 | "libc", 40 | "winapi", 41 | ] 42 | 43 | [[package]] 44 | name = "autocfg" 45 | version = "1.0.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 48 | 49 | [[package]] 50 | name = "bytes" 51 | version = "0.5.4" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" 54 | 55 | [[package]] 56 | name = "cfg-if" 57 | version = "0.1.10" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 60 | 61 | [[package]] 62 | name = "env_logger" 63 | version = "0.7.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 66 | dependencies = [ 67 | "atty", 68 | "humantime", 69 | "log", 70 | "regex", 71 | "termcolor", 72 | ] 73 | 74 | [[package]] 75 | name = "hermit-abi" 76 | version = "0.1.14" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" 79 | dependencies = [ 80 | "libc", 81 | ] 82 | 83 | [[package]] 84 | name = "humantime" 85 | version = "1.3.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 88 | dependencies = [ 89 | "quick-error", 90 | ] 91 | 92 | [[package]] 93 | name = "lazy_static" 94 | version = "1.4.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 97 | 98 | [[package]] 99 | name = "libc" 100 | version = "0.2.71" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" 103 | 104 | [[package]] 105 | name = "log" 106 | version = "0.4.8" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 109 | dependencies = [ 110 | "cfg-if", 111 | ] 112 | 113 | [[package]] 114 | name = "memchr" 115 | version = "2.5.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 118 | 119 | [[package]] 120 | name = "native" 121 | version = "0.0.1" 122 | dependencies = [ 123 | "android_logger", 124 | "bytes", 125 | "env_logger", 126 | "log", 127 | "num-derive", 128 | "num-traits", 129 | "protobuf", 130 | ] 131 | 132 | [[package]] 133 | name = "num-derive" 134 | version = "0.3.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" 137 | dependencies = [ 138 | "proc-macro2", 139 | "quote", 140 | "syn", 141 | ] 142 | 143 | [[package]] 144 | name = "num-traits" 145 | version = "0.2.12" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" 148 | dependencies = [ 149 | "autocfg", 150 | ] 151 | 152 | [[package]] 153 | name = "proc-macro2" 154 | version = "1.0.9" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" 157 | dependencies = [ 158 | "unicode-xid", 159 | ] 160 | 161 | [[package]] 162 | name = "protobuf" 163 | version = "2.14.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" 166 | dependencies = [ 167 | "bytes", 168 | ] 169 | 170 | [[package]] 171 | name = "quick-error" 172 | version = "1.2.3" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 175 | 176 | [[package]] 177 | name = "quote" 178 | version = "1.0.3" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 181 | dependencies = [ 182 | "proc-macro2", 183 | ] 184 | 185 | [[package]] 186 | name = "regex" 187 | version = "1.5.6" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" 190 | dependencies = [ 191 | "aho-corasick", 192 | "memchr", 193 | "regex-syntax", 194 | ] 195 | 196 | [[package]] 197 | name = "regex-syntax" 198 | version = "0.6.26" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" 201 | 202 | [[package]] 203 | name = "syn" 204 | version = "1.0.17" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" 207 | dependencies = [ 208 | "proc-macro2", 209 | "quote", 210 | "unicode-xid", 211 | ] 212 | 213 | [[package]] 214 | name = "termcolor" 215 | version = "1.1.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 218 | dependencies = [ 219 | "winapi-util", 220 | ] 221 | 222 | [[package]] 223 | name = "unicode-xid" 224 | version = "0.2.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 227 | 228 | [[package]] 229 | name = "winapi" 230 | version = "0.3.8" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 233 | dependencies = [ 234 | "winapi-i686-pc-windows-gnu", 235 | "winapi-x86_64-pc-windows-gnu", 236 | ] 237 | 238 | [[package]] 239 | name = "winapi-i686-pc-windows-gnu" 240 | version = "0.4.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 243 | 244 | [[package]] 245 | name = "winapi-util" 246 | version = "0.1.5" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 249 | dependencies = [ 250 | "winapi", 251 | ] 252 | 253 | [[package]] 254 | name = "winapi-x86_64-pc-windows-gnu" 255 | version = "0.4.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 258 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # need min Android API 23 (for GNU-style dynamic link lib hashing, whatever that is - rust only outputs libs in this format) 2 | # need to install crates cbindgen, cargo-ndk 3 | 4 | .DEFAULT_GOAL := help 5 | PROJECTNAME=$(shell basename "$(PWD)") 6 | SOURCES=$(sort $(wildcard ./src/*.rs ./src/**/*.rs)) 7 | 8 | OS_NAME=$(shell uname | tr '[:upper:]' '[:lower:]') 9 | PATH := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin:$(PATH) 10 | 11 | ANDROID_AARCH64_LINKER=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin/aarch64-linux-android29-clang 12 | ANDROID_ARMV7_LINKER=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin/armv7a-linux-androideabi29-clang 13 | ANDROID_I686_LINKER=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin/i686-linux-android29-clang 14 | 15 | SHELL := /bin/bash 16 | 17 | .PHONY: help 18 | help: makefile 19 | @echo 20 | @echo " Available actions in "$(PROJECTNAME)":" 21 | @echo 22 | @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' 23 | @echo 24 | 25 | # init: Ensure build dependencies are available. 26 | .PHONY: init 27 | init: 28 | cd native 29 | @if [ $$(uname) == "Darwin" ] ; then cargo install cargo-lipo ; fi 30 | cargo install cbindgen 31 | cargo install cargo-ndk 32 | cargo install protobuf-codegen 33 | @if [ $$(uname) == "Darwin" ] ; then \ 34 | rustup target add aarch64-apple-ios x86_64-apple-ios ; \ 35 | fi 36 | rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android 37 | 38 | # clean: 39 | .PHONY: clean 40 | clean: 41 | rm -rf build 42 | rm -rf release 43 | rm -f android/app/src/main/jniLibs/arm64-v8a/* 44 | rm -f android/app/src/main/jniLibs/armeabi-v7a/* 45 | rm -f android/app/src/main/jniLibs/x86/* 46 | flutter clean 47 | flutter pub get 48 | flutter pub upgrade 49 | cd native ; cargo clean 50 | 51 | # all: Compile iOS, Android, and bindings targets, and generate protobuf source files 52 | # for shared messages 53 | all: protos android-debug ios-debug bindings install 54 | 55 | all-android: protos android-debug bindings install 56 | 57 | all-ios: clean ios-debug bindings target/install-ios-debug target/install-ios-bindings 58 | # TODO: protos doesn't build on macOS, due to differences in the supplied awk I think 59 | 60 | # ios: Compile the iOS universal library 61 | ios-debug: #$(SOURCES) ndk-home 62 | @if [ $$(uname) == "Darwin" ] ; then \ 63 | cd native ; \ 64 | cargo lipo ; \ 65 | else echo "Skipping iOS compilation on $$(uname)" ; \ 66 | fi 67 | 68 | # android: Compile the android targets (arm64, armv7 and i686) 69 | android-debug: aarch64-linux-android-debug armv7-linux-androideabi-debug i686-linux-android-debug 70 | 71 | aarch64-linux-android-debug: $(SOURCES) ndk-home 72 | cd native ; \ 73 | CC_aarch64_linux_android=$(ANDROID_AARCH64_LINKER) \ 74 | CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$(ANDROID_AARCH64_LINKER) \ 75 | cargo build --target aarch64-linux-android 76 | 77 | armv7-linux-androideabi-debug: $(SOURCES) ndk-home 78 | cd native ; \ 79 | CC_armv7_linux_androideabi=$(ANDROID_ARMV7_LINKER) \ 80 | CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=$(ANDROID_ARMV7_LINKER) \ 81 | cargo build --target armv7-linux-androideabi 82 | 83 | i686-linux-android-debug: $(SOURCES) ndk-home 84 | cd native ; \ 85 | CC_i686_linux_android=$(ANDROID_I686_LINKER) \ 86 | CARGO_TARGET_I686_LINUX_ANDROID_LINKER=$(ANDROID_I686_LINKER) \ 87 | cargo build --target i686-linux-android 88 | 89 | .PHONY: ndk-home 90 | ndk-home: 91 | @if [ ! -d "${ANDROID_NDK_HOME}" ] ; then \ 92 | echo "Error: Please, set the ANDROID_NDK_HOME env variable to point to your NDK folder" ; \ 93 | exit 1 ; \ 94 | fi 95 | 96 | # protos: Generate dart protobuf source files for shared messages 97 | .PHONY: protos 98 | protos: target/dart_protos target/rust_protos 99 | 100 | target/dart_protos: 101 | rm -rf lib/protos 102 | mkdir lib/protos 103 | mkdir lib/protos/lib 104 | mkdir lib/protos/lib/src 105 | 106 | echo "// Auto-generated by makefile. Do not edit by hand." > lib/protos/lib/protos.dart 107 | echo "library shared_ffi_protos;" >> lib/protos/lib/protos.dart 108 | echo "import 'package:protobuf/protobuf.dart' as protobuf;" >> lib/protos/lib/protos.dart 109 | 110 | echo "name: shared_ffi_protos" > lib/protos/pubspec.yaml 111 | echo "description: Auto-generated protobuf messages shared across FFI" >> lib/protos/pubspec.yaml 112 | echo "version: 1.0.0" >> lib/protos/pubspec.yaml 113 | echo "environment:" >> lib/protos/pubspec.yaml 114 | echo " sdk: '>=2.8.0 <3.0.0'" >> lib/protos/pubspec.yaml 115 | echo "dependencies:" >> lib/protos/pubspec.yaml 116 | echo " protobuf: ^1.0.1" >> lib/protos/pubspec.yaml 117 | echo " grpc: ^2.2.0" >> lib/protos/pubspec.yaml 118 | 119 | ALL_PACKAGES="" 120 | ALL_MESSAGES="" 121 | ALL_COMMA_SEPARATED="" 122 | 123 | for PROTO in protos/*.proto ; do \ 124 | FILE_NAME=$$(basename "$$PROTO" .proto) ; \ 125 | protoc --proto_path=protos --dart_out=grpc:"lib/protos/lib/src/" "protos/$$FILE_NAME.proto" ; \ 126 | echo "import 'src/$$FILE_NAME.pb.dart';" >> lib/protos/lib/protos.dart ; \ 127 | echo "export 'src/$$FILE_NAME.pb.dart';" >> lib/protos/lib/protos.dart ; \ 128 | if test -f "lib/protos/lib/src/$$FILE_NAME.pbgrpc.dart" ; then \ 129 | echo "export 'src/$$FILE_NAME.pbgrpc.dart';" >> lib/protos/lib/protos.dart ; \ 130 | fi ; \ 131 | PACKAGE=$$(awk '{if (match($$0, /package (.*);/, arr) > 0) print arr[1] }' "protos/$$FILE_NAME.proto") ; \ 132 | MESSAGES=$$(awk '{if (match($$0, /message (.*)\s*{/, arr) > 0) print arr[1] }' "protos/$$FILE_NAME.proto") ; \ 133 | COMMA_SEPARATED=$$(awk '{if (match($$0, /message (.*)\s*{/, arr) > 0) print arr[1] ", " }' "protos/$$FILE_NAME.proto") ; \ 134 | BUILDERS=$$(awk '{ if (match($$0, /message (.*)\s*{/, arr) > 0) { sub(" ", "", arr[1]); printf "() => new %s(), ", arr[1] } }' "protos/$$FILE_NAME.proto") ; \ 135 | TYPES=$$(awk '{if (match($$0, /message (.*)\s*{/, arr) > 0) print "MessageType." arr[1] ", " }' "protos/$$FILE_NAME.proto") ; \ 136 | SERVICES=$$(awk '{if (match($$0, /service (.*)\s*{/, arr) > 0) print arr[1] }' "protos/$$FILE_NAME.proto" | tr " " "\n") ; \ 137 | RPCS="" ; \ 138 | for SERVICE in $$SERVICES ; do \ 139 | RPCS+="//:service $$SERVICE {" ; \ 140 | RPCS+=$$(awk -v pattern="service $$SERVICE {" -v FS=$$'\b' -v RS=$$'\177' 'END { startOfService = match($$0, pattern); remainder = substr($$0, startOfService); endOfService = match(remainder, /\n\}/); serviceDefinition = substr(remainder, 0, endOfService + 1); patsplit(serviceDefinition, rpcs, /(rpc[^\n]*)/); for (i in rpcs) { printf "//:%s ", rpcs[i] } }' "protos/$$FILE_NAME.proto") ; \ 141 | RPCS+="}" ; \ 142 | done ; \ 143 | ALL_PACKAGES+=$$(echo "processOnePackage(\"$$PACKAGE\", \"\"\"$$MESSAGES\"\"\", [$$TYPES], [$$BUILDERS], \"\"\"$$RPCS\"\"\");") ; \ 144 | ALL_MESSAGES+=$$MESSAGES ; \ 145 | ALL_COMMA_SEPARATED+=$$COMMA_SEPARATED ; \ 146 | done ; \ 147 | echo "void createServiceIndexEntries(void processOnePackage(String package, String messages, List types, List builders, String rpcs)) {" >> lib/protos/lib/protos.dart ; \ 148 | echo $$ALL_PACKAGES >> lib/protos/lib/protos.dart ; \ 149 | echo "}" >> lib/protos/lib/protos.dart ; \ 150 | echo "enum MessageType {" >> lib/protos/lib/protos.dart ; \ 151 | echo $$ALL_COMMA_SEPARATED >> lib/protos/lib/protos.dart ; \ 152 | echo "}" >> lib/protos/lib/protos.dart 153 | 154 | dartfmt -w lib/protos/lib/protos.dart 155 | cd lib/protos ; pub get ; pub upgrade 156 | 157 | target/rust_protos: 158 | rm -rf native/src/protos 159 | mkdir native/src/protos 160 | echo "// Auto-generated by makefile. Do not edit by hand." > native/src/protos/mod.rs 161 | echo "// @generated" >> native/src/protos.mod.rs 162 | 163 | ALL_COMMA_SEPARATED="" 164 | INDEX=0 165 | 166 | for PROTO in protos/*.proto ; do \ 167 | FILE_NAME=$$(basename "$$PROTO" .proto) ; \ 168 | protoc --proto_path=protos --rust_out native/src/protos/ "protos/$$FILE_NAME.proto" ; \ 169 | echo "pub mod $$FILE_NAME;" >> native/src/protos/mod.rs ; \ 170 | COMMA_SEPARATED=$$(awk -v i=$$INDEX '{if (match($$0, /message (.*)\s*{/, arr) > 0) print arr[1] "= " i ++ ", " }' "protos/$$FILE_NAME.proto") ; \ 171 | ALL_COMMA_SEPARATED+=$$COMMA_SEPARATED ; \ 172 | INDEX=$$((INDEX + $$(echo $$COMMA_SEPARATED | tr -cd ',' | wc -c))) ; \ 173 | done ; \ 174 | echo "" >> native/src/protos/mod.rs ; \ 175 | echo "use num_derive::FromPrimitive;" >> native/src/protos/mod.rs ; \ 176 | echo "" >> native/src/protos/mod.rs ; \ 177 | echo "#[derive(FromPrimitive)]" >> native/src/protos/mod.rs ; \ 178 | echo "pub enum MessageType {" >> native/src/protos/mod.rs ; \ 179 | echo " UnrecognizedMessage = -1," >> native/src/protos/mod.rs ; \ 180 | echo " " $$ALL_COMMA_SEPARATED | sed 's/, /,\n /g' >> native/src/protos/mod.rs ; \ 181 | echo "}" >> native/src/protos/mod.rs; \ 182 | 183 | # bindings: Generate the .h file for iOS 184 | bindings: target/bindings.h 185 | 186 | target/bindings.h: $(SOURCES) 187 | cd native ; \ 188 | cbindgen --config cbindgen.toml --crate native | grep -v \#include | uniq > $@ 189 | 190 | # install: Place generated artifacts into correct android and ios build locations 191 | .PHONY: install 192 | install: target/install-android-debug target/install-ios-debug target/install-ios-bindings 193 | 194 | target/install-android-debug: 195 | cp native/target/aarch64-linux-android/debug/libnative.so android/app/src/main/jniLibs/arm64-v8a/libnative.so 196 | cp native/target/armv7-linux-androideabi/debug/libnative.so android/app/src/main/jniLibs/armeabi-v7a/libnative.so 197 | cp native/target/i686-linux-android/debug/libnative.so android/app/src/main/jniLibs/x86/libnative.so 198 | 199 | target/install-ios-debug: 200 | @if [ $$(uname) == "Darwin" ] ; then \ 201 | cp native/target/universal/debug/libnative.a ios/libnative.a ; \ 202 | else echo "Skipping iOS library installation on $$(uname)" ; \ 203 | fi 204 | 205 | target/install-ios-bindings: 206 | cp native/target/bindings.h ios/Classes/NativePlugin.h 207 | -------------------------------------------------------------------------------- /lib/bridge.dart: -------------------------------------------------------------------------------- 1 | part of app; 2 | 3 | typedef void ResponseHandler(int responseMessageTypeValue, int inReplyToId, 4 | Uint8List payload, bool isResponseStreamComplete); 5 | 6 | typedef InitializeFFI = void Function(); 7 | 8 | typedef InitializeFFINativeReceiver = Void Function(); 9 | 10 | typedef ReceiveProtobufFromFFI = Void Function( 11 | Int32 requestMessageType, 12 | Int32 inReplyToId, 13 | Pointer payloadBuffer, 14 | IntPtr payloadBufferLength, 15 | Uint8 isPayloadStreamComplete); 16 | 17 | typedef SendProtobufToFFI = void Function( 18 | int requestMessageType, 19 | int requestMessageId, 20 | Pointer payloadBuffer, 21 | int payloadBufferLength, 22 | int expectedResponseMessageType, 23 | Pointer>); 24 | 25 | typedef SendProtobufToFFINativeReceiver = Void Function( 26 | Int32 request_message_type, 27 | Int32 request_message_id, 28 | Pointer payload_buffer, 29 | IntPtr payload_buffer_length, 30 | Int32 expected_response_message_type, 31 | Pointer>); 32 | 33 | class NativeFFIBridge { 34 | static final NativeFFIBridge _singleton = new NativeFFIBridge._(); 35 | 36 | static final DynamicLibrary _nativeLibrary = Platform.isAndroid 37 | ? DynamicLibrary.open("libnative.so") 38 | : DynamicLibrary.process(); 39 | 40 | static final InitializeFFI _initializeFFI = _nativeLibrary 41 | .lookup>("initialize_ffi") 42 | .asFunction(); 43 | 44 | static final SendProtobufToFFI _sendToFFI = _nativeLibrary 45 | .lookup>( 46 | "receive_from_ffi") 47 | .asFunction(); 48 | 49 | NativeFFIBridge._() { 50 | final start = DateTime.now(); 51 | 52 | print("Initializing NativeFFIBridge."); 53 | 54 | if (_nativeLibrary == null) { 55 | print("Error: Native library not available, check build and packaging."); 56 | } else { 57 | _initializeFFI(); 58 | 59 | print("Native library ${_nativeLibrary.toString()} loaded and ready."); 60 | 61 | // Dart does not initialize static finals until their first access. 62 | // Force initialization now. 63 | 64 | _serviceIndex; 65 | _rpcClientChannel; 66 | 67 | final startup = DateTime.now().difference(start).inMilliseconds; 68 | 69 | print("NativeFFIBridge initialized in ${startup}ms."); 70 | } 71 | } 72 | 73 | factory NativeFFIBridge() => _singleton; 74 | 75 | static int _id = 0; 76 | 77 | static int _getNextMessageId() => _id++; 78 | 79 | static final NativeFFIRPCClientChannel _rpcClientChannel = 80 | new NativeFFIRPCClientChannel(); 81 | 82 | static final ProtobufServiceIndex _serviceIndex = new ProtobufServiceIndex(); 83 | 84 | NativeFFIRPCClientChannel get rpcClientChannel => _rpcClientChannel; 85 | 86 | static final _unrecognized = new UnrecognizedMessageException(); 87 | 88 | void announce(T message) => _announceRaw( 89 | _serviceIndex 90 | .getMessageTypeForMessage(message) 91 | .flatMap(_serviceIndex.getIntValueFromMessageType) 92 | .orElse(-1), 93 | message.writeToBuffer()); 94 | 95 | void _announceRaw(int requestType, List payload) => _send( 96 | requestType, _getNextMessageId(), 0, payload, -1, (_, __, ___, ____) {}); 97 | 98 | void streamAnnounce(Stream messages) => 99 | messages.listen(announce); 100 | 101 | Future request( 102 | S request) => 103 | _serviceIndex.getMessageTypeForMessageClass().cond( 104 | (expectedResponseType) => _requestRaw( 105 | _serviceIndex 106 | .getMessageTypeForMessage(request) 107 | .flatMap(_serviceIndex.getIntValueFromMessageType) 108 | .orElse(-1), 109 | Stream.value(request.writeToBuffer()), 110 | _serviceIndex 111 | .getIntValueFromMessageType(expectedResponseType) 112 | .orElse(-1)) 113 | .last 114 | .then((message) => message as R), 115 | () => Future.error(_unrecognized)); 116 | 117 | Stream _requestRaw( 118 | int requestType, Stream payload, int expectedResponseType) { 119 | final StreamController controller = 120 | new StreamController(); 121 | 122 | final int id = _getNextMessageId(); 123 | 124 | int sequence = 0; 125 | 126 | payload.listen((requestPayload) => 127 | _send(requestType, id, sequence++, requestPayload, expectedResponseType, 128 | (messageType, inReplyToId, responsePayload, 129 | isResponseStreamComplete) { 130 | _serviceIndex 131 | .getMessageTypeFromIntValue(expectedResponseType) 132 | .flatMap((type) => _serviceIndex.getDecodedPayloadFromMessageType( 133 | type, responsePayload)) 134 | .ifPresent(controller.add); 135 | 136 | if (isResponseStreamComplete) { 137 | controller.close(); 138 | } 139 | })); 140 | 141 | return controller.stream; 142 | } 143 | 144 | Future streamRequest(Stream requests) => 146 | _serviceIndex.getMessageTypeForMessageClass().cond( 147 | (requestType) => _serviceIndex 148 | .getMessageTypeForMessageClass() 149 | .cond( 150 | (expectedResponseType) => _requestRaw( 151 | _serviceIndex 152 | .getIntValueFromMessageType(requestType) 153 | .orElse(-1), 154 | requests.map((request) => request.writeToBuffer()), 155 | _serviceIndex 156 | .getIntValueFromMessageType(expectedResponseType) 157 | .orElse(-1)) 158 | .last 159 | .then((message) => message as R), 160 | () => Future.error(_unrecognized)), 161 | () => Future.error(_unrecognized)); 162 | 163 | Stream requestStreamResponse(S request) => 165 | _serviceIndex.getMessageTypeForMessageClass().cond( 166 | (expectedResponseType) => _requestRaw( 167 | _serviceIndex 168 | .getMessageTypeForMessage(request) 169 | .flatMap(_serviceIndex.getIntValueFromMessageType) 170 | .orElse(-1), 171 | Stream.value(request.writeToBuffer()), 172 | _serviceIndex 173 | .getIntValueFromMessageType(expectedResponseType) 174 | .orElse(-1)) 175 | .map((message) => message as R), 176 | () => Stream.error(_unrecognized)); 177 | 178 | Stream streamRequestStreamResponse(Stream requests) => 180 | _serviceIndex.getMessageTypeForMessageClass().cond( 181 | (requestType) => _serviceIndex 182 | .getMessageTypeForMessageClass() 183 | .cond( 184 | (expectedResponseType) => _requestRaw( 185 | _serviceIndex 186 | .getIntValueFromMessageType(requestType) 187 | .orElse(-1), 188 | requests.map((request) => request.writeToBuffer()), 189 | _serviceIndex 190 | .getIntValueFromMessageType(expectedResponseType) 191 | .orElse(-1)) 192 | .map((message) => message as R), 193 | () => Stream.error(_unrecognized)), 194 | () => Stream.error(_unrecognized)); 195 | 196 | void requestAndHandle( 197 | T request, MessageType expectedResponseType, ResponseHandler callback) { 198 | final int id = _getNextMessageId(); 199 | 200 | _send( 201 | _serviceIndex 202 | .getMessageTypeForMessage(request) 203 | .flatMap(_serviceIndex.getIntValueFromMessageType) 204 | .orElse(-1), 205 | id, 206 | 0, 207 | request.writeToBuffer(), 208 | _serviceIndex 209 | .getIntValueFromMessageType(expectedResponseType) 210 | .orElse(-1), 211 | callback); 212 | } 213 | 214 | static final Map _pendingResponseHandlers = 215 | new Map(); 216 | 217 | static void _send( 218 | int requestMessageType, 219 | int messageId, 220 | int sequenceId, 221 | Uint8List payload, 222 | int expectedResponseMessageType, 223 | ResponseHandler handler) { 224 | _pendingResponseHandlers[messageId] = handler; 225 | 226 | final serializationBuffer = Uint8Array.fromTypedList(payload); 227 | 228 | // TODO: we don't currently deliver sequenceId to native, nor to we indicate 229 | // to native whether our requests are part of a stream or not (although we 230 | // do deliver all requests in order with the same messageId) 231 | // TODO: native always indicates its response is the end of a stream 232 | // TODO: grpc rpcs with streaming responses not currently implemented - native 233 | // only ever sends a single response 234 | 235 | _sendToFFI( 236 | requestMessageType, 237 | messageId, 238 | serializationBuffer.rawPtr, 239 | serializationBuffer.length, 240 | expectedResponseMessageType, 241 | Pointer.fromFunction(_receive), 242 | ); 243 | 244 | serializationBuffer.free(); 245 | } 246 | 247 | static void _receive( 248 | int responseMessageType, 249 | int inReplyToMessageId, 250 | Pointer payloadBuffer, 251 | int payloadBufferLength, 252 | int isPayloadStreamComplete) { 253 | final handler = _pendingResponseHandlers[inReplyToMessageId]; 254 | 255 | if (handler != null) { 256 | handler( 257 | responseMessageType, 258 | inReplyToMessageId, 259 | payloadBuffer.asTypedList(payloadBufferLength), 260 | isPayloadStreamComplete == 1); 261 | 262 | if (isPayloadStreamComplete == 1) { 263 | _pendingResponseHandlers.remove(inReplyToMessageId); 264 | } 265 | } 266 | } 267 | } 268 | 269 | class UnrecognizedMessageException implements Exception {} 270 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "4.0.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "0.39.10" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.6.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.4.1" 32 | build: 33 | dependency: transitive 34 | description: 35 | name: build 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.3.0" 39 | build_config: 40 | dependency: transitive 41 | description: 42 | name: build_config 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.4.2" 46 | build_daemon: 47 | dependency: transitive 48 | description: 49 | name: build_daemon 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.1.4" 53 | build_resolvers: 54 | dependency: transitive 55 | description: 56 | name: build_resolvers 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.3.9" 60 | build_runner: 61 | dependency: "direct dev" 62 | description: 63 | name: build_runner 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.10.0" 67 | build_runner_core: 68 | dependency: transitive 69 | description: 70 | name: build_runner_core 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "5.2.0" 74 | built_collection: 75 | dependency: transitive 76 | description: 77 | name: built_collection 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "4.3.2" 81 | built_value: 82 | dependency: transitive 83 | description: 84 | name: built_value 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "7.1.0" 88 | charcode: 89 | dependency: transitive 90 | description: 91 | name: charcode 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.1.3" 95 | checked_yaml: 96 | dependency: transitive 97 | description: 98 | name: checked_yaml 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.0.2" 102 | code_builder: 103 | dependency: transitive 104 | description: 105 | name: code_builder 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "3.3.0" 109 | collection: 110 | dependency: transitive 111 | description: 112 | name: collection 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.14.12" 116 | convert: 117 | dependency: transitive 118 | description: 119 | name: convert 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "2.1.1" 123 | crypto: 124 | dependency: transitive 125 | description: 126 | name: crypto 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "2.1.5" 130 | csslib: 131 | dependency: transitive 132 | description: 133 | name: csslib 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "0.16.1" 137 | cupertino_icons: 138 | dependency: "direct main" 139 | description: 140 | name: cupertino_icons 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "0.1.3" 144 | dart_style: 145 | dependency: transitive 146 | description: 147 | name: dart_style 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "1.3.6" 151 | ffi: 152 | dependency: "direct main" 153 | description: 154 | name: ffi 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "0.1.3" 158 | ffi_helper: 159 | dependency: "direct main" 160 | description: 161 | name: ffi_helper 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "1.4.0" 165 | fixnum: 166 | dependency: transitive 167 | description: 168 | name: fixnum 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "0.10.11" 172 | flutter: 173 | dependency: "direct main" 174 | description: flutter 175 | source: sdk 176 | version: "0.0.0" 177 | glob: 178 | dependency: transitive 179 | description: 180 | name: glob 181 | url: "https://pub.dartlang.org" 182 | source: hosted 183 | version: "1.2.0" 184 | googleapis_auth: 185 | dependency: transitive 186 | description: 187 | name: googleapis_auth 188 | url: "https://pub.dartlang.org" 189 | source: hosted 190 | version: "0.2.12" 191 | graphs: 192 | dependency: transitive 193 | description: 194 | name: graphs 195 | url: "https://pub.dartlang.org" 196 | source: hosted 197 | version: "0.2.0" 198 | grpc: 199 | dependency: "direct main" 200 | description: 201 | name: grpc 202 | url: "https://pub.dartlang.org" 203 | source: hosted 204 | version: "2.2.0" 205 | html: 206 | dependency: transitive 207 | description: 208 | name: html 209 | url: "https://pub.dartlang.org" 210 | source: hosted 211 | version: "0.14.0+3" 212 | http: 213 | dependency: transitive 214 | description: 215 | name: http 216 | url: "https://pub.dartlang.org" 217 | source: hosted 218 | version: "0.12.1" 219 | http2: 220 | dependency: transitive 221 | description: 222 | name: http2 223 | url: "https://pub.dartlang.org" 224 | source: hosted 225 | version: "1.0.0" 226 | http_multi_server: 227 | dependency: transitive 228 | description: 229 | name: http_multi_server 230 | url: "https://pub.dartlang.org" 231 | source: hosted 232 | version: "2.2.0" 233 | http_parser: 234 | dependency: transitive 235 | description: 236 | name: http_parser 237 | url: "https://pub.dartlang.org" 238 | source: hosted 239 | version: "3.1.4" 240 | io: 241 | dependency: transitive 242 | description: 243 | name: io 244 | url: "https://pub.dartlang.org" 245 | source: hosted 246 | version: "0.3.4" 247 | js: 248 | dependency: transitive 249 | description: 250 | name: js 251 | url: "https://pub.dartlang.org" 252 | source: hosted 253 | version: "0.6.2" 254 | json_annotation: 255 | dependency: transitive 256 | description: 257 | name: json_annotation 258 | url: "https://pub.dartlang.org" 259 | source: hosted 260 | version: "3.0.1" 261 | logging: 262 | dependency: transitive 263 | description: 264 | name: logging 265 | url: "https://pub.dartlang.org" 266 | source: hosted 267 | version: "0.11.4" 268 | matcher: 269 | dependency: transitive 270 | description: 271 | name: matcher 272 | url: "https://pub.dartlang.org" 273 | source: hosted 274 | version: "0.12.8" 275 | meta: 276 | dependency: transitive 277 | description: 278 | name: meta 279 | url: "https://pub.dartlang.org" 280 | source: hosted 281 | version: "1.1.8" 282 | mime: 283 | dependency: transitive 284 | description: 285 | name: mime 286 | url: "https://pub.dartlang.org" 287 | source: hosted 288 | version: "0.9.6+3" 289 | node_interop: 290 | dependency: transitive 291 | description: 292 | name: node_interop 293 | url: "https://pub.dartlang.org" 294 | source: hosted 295 | version: "1.1.1" 296 | node_io: 297 | dependency: transitive 298 | description: 299 | name: node_io 300 | url: "https://pub.dartlang.org" 301 | source: hosted 302 | version: "1.1.1" 303 | package_config: 304 | dependency: transitive 305 | description: 306 | name: package_config 307 | url: "https://pub.dartlang.org" 308 | source: hosted 309 | version: "1.9.3" 310 | path: 311 | dependency: transitive 312 | description: 313 | name: path 314 | url: "https://pub.dartlang.org" 315 | source: hosted 316 | version: "1.7.0" 317 | pedantic: 318 | dependency: transitive 319 | description: 320 | name: pedantic 321 | url: "https://pub.dartlang.org" 322 | source: hosted 323 | version: "1.9.0" 324 | pool: 325 | dependency: transitive 326 | description: 327 | name: pool 328 | url: "https://pub.dartlang.org" 329 | source: hosted 330 | version: "1.4.0" 331 | protobuf: 332 | dependency: "direct main" 333 | description: 334 | name: protobuf 335 | url: "https://pub.dartlang.org" 336 | source: hosted 337 | version: "1.0.1" 338 | pub_semver: 339 | dependency: transitive 340 | description: 341 | name: pub_semver 342 | url: "https://pub.dartlang.org" 343 | source: hosted 344 | version: "1.4.4" 345 | pubspec_parse: 346 | dependency: transitive 347 | description: 348 | name: pubspec_parse 349 | url: "https://pub.dartlang.org" 350 | source: hosted 351 | version: "0.1.5" 352 | quiver: 353 | dependency: transitive 354 | description: 355 | name: quiver 356 | url: "https://pub.dartlang.org" 357 | source: hosted 358 | version: "2.1.3" 359 | shared_ffi_protos: 360 | dependency: "direct main" 361 | description: 362 | path: "lib/protos" 363 | relative: true 364 | source: path 365 | version: "1.0.0" 366 | shelf: 367 | dependency: transitive 368 | description: 369 | name: shelf 370 | url: "https://pub.dartlang.org" 371 | source: hosted 372 | version: "0.7.6" 373 | shelf_web_socket: 374 | dependency: transitive 375 | description: 376 | name: shelf_web_socket 377 | url: "https://pub.dartlang.org" 378 | source: hosted 379 | version: "0.2.3" 380 | sky_engine: 381 | dependency: transitive 382 | description: flutter 383 | source: sdk 384 | version: "0.0.99" 385 | source_span: 386 | dependency: transitive 387 | description: 388 | name: source_span 389 | url: "https://pub.dartlang.org" 390 | source: hosted 391 | version: "1.7.0" 392 | stack_trace: 393 | dependency: transitive 394 | description: 395 | name: stack_trace 396 | url: "https://pub.dartlang.org" 397 | source: hosted 398 | version: "1.9.3" 399 | stream_channel: 400 | dependency: transitive 401 | description: 402 | name: stream_channel 403 | url: "https://pub.dartlang.org" 404 | source: hosted 405 | version: "2.0.0" 406 | stream_transform: 407 | dependency: transitive 408 | description: 409 | name: stream_transform 410 | url: "https://pub.dartlang.org" 411 | source: hosted 412 | version: "1.2.0" 413 | string_scanner: 414 | dependency: transitive 415 | description: 416 | name: string_scanner 417 | url: "https://pub.dartlang.org" 418 | source: hosted 419 | version: "1.0.5" 420 | term_glyph: 421 | dependency: transitive 422 | description: 423 | name: term_glyph 424 | url: "https://pub.dartlang.org" 425 | source: hosted 426 | version: "1.1.0" 427 | timing: 428 | dependency: transitive 429 | description: 430 | name: timing 431 | url: "https://pub.dartlang.org" 432 | source: hosted 433 | version: "0.1.1+2" 434 | typed_data: 435 | dependency: transitive 436 | description: 437 | name: typed_data 438 | url: "https://pub.dartlang.org" 439 | source: hosted 440 | version: "1.1.6" 441 | vector_math: 442 | dependency: transitive 443 | description: 444 | name: vector_math 445 | url: "https://pub.dartlang.org" 446 | source: hosted 447 | version: "2.0.8" 448 | watcher: 449 | dependency: transitive 450 | description: 451 | name: watcher 452 | url: "https://pub.dartlang.org" 453 | source: hosted 454 | version: "0.9.7+15" 455 | web_socket_channel: 456 | dependency: transitive 457 | description: 458 | name: web_socket_channel 459 | url: "https://pub.dartlang.org" 460 | source: hosted 461 | version: "1.1.0" 462 | yaml: 463 | dependency: transitive 464 | description: 465 | name: yaml 466 | url: "https://pub.dartlang.org" 467 | source: hosted 468 | version: "2.2.1" 469 | sdks: 470 | dart: ">=2.8.0 <3.0.0" 471 | -------------------------------------------------------------------------------- /native/src/protos/greeting.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 2.14.0. Do not edit 2 | // @generated 3 | 4 | // https://github.com/rust-lang/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | //! Generated file from `greeting.proto` 21 | 22 | use protobuf::Message as Message_imported_for_functions; 23 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 24 | 25 | /// Generated files are compatible only with the same version 26 | /// of protobuf runtime. 27 | // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_14_0; 28 | 29 | #[derive(PartialEq,Clone,Default)] 30 | pub struct HelloRequest { 31 | // message fields 32 | pub name: ::std::string::String, 33 | // special fields 34 | pub unknown_fields: ::protobuf::UnknownFields, 35 | pub cached_size: ::protobuf::CachedSize, 36 | } 37 | 38 | impl<'a> ::std::default::Default for &'a HelloRequest { 39 | fn default() -> &'a HelloRequest { 40 | ::default_instance() 41 | } 42 | } 43 | 44 | impl HelloRequest { 45 | pub fn new() -> HelloRequest { 46 | ::std::default::Default::default() 47 | } 48 | 49 | // string name = 1; 50 | 51 | 52 | pub fn get_name(&self) -> &str { 53 | &self.name 54 | } 55 | pub fn clear_name(&mut self) { 56 | self.name.clear(); 57 | } 58 | 59 | // Param is passed by value, moved 60 | pub fn set_name(&mut self, v: ::std::string::String) { 61 | self.name = v; 62 | } 63 | 64 | // Mutable pointer to the field. 65 | // If field is not initialized, it is initialized with default value first. 66 | pub fn mut_name(&mut self) -> &mut ::std::string::String { 67 | &mut self.name 68 | } 69 | 70 | // Take field 71 | pub fn take_name(&mut self) -> ::std::string::String { 72 | ::std::mem::replace(&mut self.name, ::std::string::String::new()) 73 | } 74 | } 75 | 76 | impl ::protobuf::Message for HelloRequest { 77 | fn is_initialized(&self) -> bool { 78 | true 79 | } 80 | 81 | fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { 82 | while !is.eof()? { 83 | let (field_number, wire_type) = is.read_tag_unpack()?; 84 | match field_number { 85 | 1 => { 86 | ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; 87 | }, 88 | _ => { 89 | ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; 90 | }, 91 | }; 92 | } 93 | ::std::result::Result::Ok(()) 94 | } 95 | 96 | // Compute sizes of nested messages 97 | #[allow(unused_variables)] 98 | fn compute_size(&self) -> u32 { 99 | let mut my_size = 0; 100 | if !self.name.is_empty() { 101 | my_size += ::protobuf::rt::string_size(1, &self.name); 102 | } 103 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 104 | self.cached_size.set(my_size); 105 | my_size 106 | } 107 | 108 | fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { 109 | if !self.name.is_empty() { 110 | os.write_string(1, &self.name)?; 111 | } 112 | os.write_unknown_fields(self.get_unknown_fields())?; 113 | ::std::result::Result::Ok(()) 114 | } 115 | 116 | fn get_cached_size(&self) -> u32 { 117 | self.cached_size.get() 118 | } 119 | 120 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 121 | &self.unknown_fields 122 | } 123 | 124 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 125 | &mut self.unknown_fields 126 | } 127 | 128 | fn as_any(&self) -> &dyn (::std::any::Any) { 129 | self as &dyn (::std::any::Any) 130 | } 131 | fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { 132 | self as &mut dyn (::std::any::Any) 133 | } 134 | fn into_any(self: Box) -> ::std::boxed::Box { 135 | self 136 | } 137 | 138 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 139 | Self::descriptor_static() 140 | } 141 | 142 | fn new() -> HelloRequest { 143 | HelloRequest::new() 144 | } 145 | 146 | fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { 147 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy::INIT; 148 | unsafe { 149 | descriptor.get(|| { 150 | let mut fields = ::std::vec::Vec::new(); 151 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( 152 | "name", 153 | |m: &HelloRequest| { &m.name }, 154 | |m: &mut HelloRequest| { &mut m.name }, 155 | )); 156 | ::protobuf::reflect::MessageDescriptor::new_pb_name::( 157 | "HelloRequest", 158 | fields, 159 | file_descriptor_proto() 160 | ) 161 | }) 162 | } 163 | } 164 | 165 | fn default_instance() -> &'static HelloRequest { 166 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy::INIT; 167 | unsafe { 168 | instance.get(HelloRequest::new) 169 | } 170 | } 171 | } 172 | 173 | impl ::protobuf::Clear for HelloRequest { 174 | fn clear(&mut self) { 175 | self.name.clear(); 176 | self.unknown_fields.clear(); 177 | } 178 | } 179 | 180 | impl ::std::fmt::Debug for HelloRequest { 181 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 182 | ::protobuf::text_format::fmt(self, f) 183 | } 184 | } 185 | 186 | impl ::protobuf::reflect::ProtobufValue for HelloRequest { 187 | fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { 188 | ::protobuf::reflect::ReflectValueRef::Message(self) 189 | } 190 | } 191 | 192 | #[derive(PartialEq,Clone,Default)] 193 | pub struct HelloResponse { 194 | // message fields 195 | pub message: ::std::string::String, 196 | // special fields 197 | pub unknown_fields: ::protobuf::UnknownFields, 198 | pub cached_size: ::protobuf::CachedSize, 199 | } 200 | 201 | impl<'a> ::std::default::Default for &'a HelloResponse { 202 | fn default() -> &'a HelloResponse { 203 | ::default_instance() 204 | } 205 | } 206 | 207 | impl HelloResponse { 208 | pub fn new() -> HelloResponse { 209 | ::std::default::Default::default() 210 | } 211 | 212 | // string message = 1; 213 | 214 | 215 | pub fn get_message(&self) -> &str { 216 | &self.message 217 | } 218 | pub fn clear_message(&mut self) { 219 | self.message.clear(); 220 | } 221 | 222 | // Param is passed by value, moved 223 | pub fn set_message(&mut self, v: ::std::string::String) { 224 | self.message = v; 225 | } 226 | 227 | // Mutable pointer to the field. 228 | // If field is not initialized, it is initialized with default value first. 229 | pub fn mut_message(&mut self) -> &mut ::std::string::String { 230 | &mut self.message 231 | } 232 | 233 | // Take field 234 | pub fn take_message(&mut self) -> ::std::string::String { 235 | ::std::mem::replace(&mut self.message, ::std::string::String::new()) 236 | } 237 | } 238 | 239 | impl ::protobuf::Message for HelloResponse { 240 | fn is_initialized(&self) -> bool { 241 | true 242 | } 243 | 244 | fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { 245 | while !is.eof()? { 246 | let (field_number, wire_type) = is.read_tag_unpack()?; 247 | match field_number { 248 | 1 => { 249 | ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.message)?; 250 | }, 251 | _ => { 252 | ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; 253 | }, 254 | }; 255 | } 256 | ::std::result::Result::Ok(()) 257 | } 258 | 259 | // Compute sizes of nested messages 260 | #[allow(unused_variables)] 261 | fn compute_size(&self) -> u32 { 262 | let mut my_size = 0; 263 | if !self.message.is_empty() { 264 | my_size += ::protobuf::rt::string_size(1, &self.message); 265 | } 266 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 267 | self.cached_size.set(my_size); 268 | my_size 269 | } 270 | 271 | fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { 272 | if !self.message.is_empty() { 273 | os.write_string(1, &self.message)?; 274 | } 275 | os.write_unknown_fields(self.get_unknown_fields())?; 276 | ::std::result::Result::Ok(()) 277 | } 278 | 279 | fn get_cached_size(&self) -> u32 { 280 | self.cached_size.get() 281 | } 282 | 283 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 284 | &self.unknown_fields 285 | } 286 | 287 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 288 | &mut self.unknown_fields 289 | } 290 | 291 | fn as_any(&self) -> &dyn (::std::any::Any) { 292 | self as &dyn (::std::any::Any) 293 | } 294 | fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { 295 | self as &mut dyn (::std::any::Any) 296 | } 297 | fn into_any(self: Box) -> ::std::boxed::Box { 298 | self 299 | } 300 | 301 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 302 | Self::descriptor_static() 303 | } 304 | 305 | fn new() -> HelloResponse { 306 | HelloResponse::new() 307 | } 308 | 309 | fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { 310 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy::INIT; 311 | unsafe { 312 | descriptor.get(|| { 313 | let mut fields = ::std::vec::Vec::new(); 314 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( 315 | "message", 316 | |m: &HelloResponse| { &m.message }, 317 | |m: &mut HelloResponse| { &mut m.message }, 318 | )); 319 | ::protobuf::reflect::MessageDescriptor::new_pb_name::( 320 | "HelloResponse", 321 | fields, 322 | file_descriptor_proto() 323 | ) 324 | }) 325 | } 326 | } 327 | 328 | fn default_instance() -> &'static HelloResponse { 329 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy::INIT; 330 | unsafe { 331 | instance.get(HelloResponse::new) 332 | } 333 | } 334 | } 335 | 336 | impl ::protobuf::Clear for HelloResponse { 337 | fn clear(&mut self) { 338 | self.message.clear(); 339 | self.unknown_fields.clear(); 340 | } 341 | } 342 | 343 | impl ::std::fmt::Debug for HelloResponse { 344 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 345 | ::protobuf::text_format::fmt(self, f) 346 | } 347 | } 348 | 349 | impl ::protobuf::reflect::ProtobufValue for HelloResponse { 350 | fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { 351 | ::protobuf::reflect::ReflectValueRef::Message(self) 352 | } 353 | } 354 | 355 | static file_descriptor_proto_data: &'static [u8] = b"\ 356 | \n\x0egreeting.proto\x12\x13com.google.greeting\"\"\n\x0cHelloRequest\ 357 | \x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\")\n\rHelloResponse\x12\ 358 | \x18\n\x07message\x18\x01\x20\x01(\tR\x07message2\xb4\x01\n\x07Greeter\ 359 | \x12Q\n\x08SayHello\x12!.com.google.greeting.HelloRequest\x1a\".com.goog\ 360 | le.greeting.HelloResponse\x12V\n\rSayHelloAgain\x12!.com.google.greeting\ 361 | .HelloRequest\x1a\".com.google.greeting.HelloResponseJ\xa9\x04\n\x06\x12\ 362 | \x04\0\0\x16\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\ 363 | \x02\0\x1c\na\n\x02\x06\0\x12\x04\x07\0\x0c\x01\x1a\"\x20The\x20greeting\ 364 | \x20service\x20definition.\n21\x20https://grpc.io/docs/languages/dart/qu\ 365 | ickstart/\n\n\n\n\x03\x06\0\x01\x12\x03\x07\x08\x0f\n\x1f\n\x04\x06\0\ 366 | \x02\0\x12\x03\t\x048\x1a\x12\x20Sends\x20a\x20greeting\n\n\x0c\n\x05\ 367 | \x06\0\x02\0\x01\x12\x03\t\x08\x10\n\x0c\n\x05\x06\0\x02\0\x02\x12\x03\t\ 368 | \x12\x1e\n\x0c\n\x05\x06\0\x02\0\x03\x12\x03\t)6\n%\n\x04\x06\0\x02\x01\ 369 | \x12\x03\x0b\x04=\x1a\x18\x20Sends\x20another\x20greeting\n\n\x0c\n\x05\ 370 | \x06\0\x02\x01\x01\x12\x03\x0b\x08\x15\n\x0c\n\x05\x06\0\x02\x01\x02\x12\ 371 | \x03\x0b\x17#\n\x0c\n\x05\x06\0\x02\x01\x03\x12\x03\x0b.;\n=\n\x02\x04\0\ 372 | \x12\x04\x0f\0\x11\x01\x1a1\x20The\x20request\x20message\x20containing\ 373 | \x20the\x20user's\x20name.\n\n\n\n\x03\x04\0\x01\x12\x03\x0f\x08\x14\n\ 374 | \x0b\n\x04\x04\0\x02\0\x12\x03\x10\x04\x14\n\x0c\n\x05\x04\0\x02\0\x05\ 375 | \x12\x03\x10\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x10\x0b\x0f\n\x0c\ 376 | \n\x05\x04\0\x02\0\x03\x12\x03\x10\x12\x13\n;\n\x02\x04\x01\x12\x04\x14\ 377 | \0\x16\x01\x1a/\x20The\x20response\x20message\x20containing\x20the\x20gr\ 378 | eetings\n\n\n\n\x03\x04\x01\x01\x12\x03\x14\x08\x15\n\x0b\n\x04\x04\x01\ 379 | \x02\0\x12\x03\x15\x04\x17\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x15\x04\ 380 | \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x15\x0b\x12\n\x0c\n\x05\x04\x01\ 381 | \x02\0\x03\x12\x03\x15\x15\x16b\x06proto3\ 382 | "; 383 | 384 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy::INIT; 385 | 386 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 387 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 388 | } 389 | 390 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 391 | unsafe { 392 | file_descriptor_proto_lazy.get(|| { 393 | parse_descriptor_proto() 394 | }) 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 18 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 19 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXCopyFilesBuildPhase section */ 23 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 24 | isa = PBXCopyFilesBuildPhase; 25 | buildActionMask = 2147483647; 26 | dstPath = ""; 27 | dstSubfolderSpec = 10; 28 | files = ( 29 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 30 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 31 | ); 32 | name = "Embed Frameworks"; 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXCopyFilesBuildPhase section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 39 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 40 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 41 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 42 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 43 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 45 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 46 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 47 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 48 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 61 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 9740EEB11CF90186004384FC /* Flutter */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 3B80C3931E831B6300D905FE /* App.framework */, 72 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 73 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 74 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 75 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 76 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 77 | ); 78 | name = Flutter; 79 | sourceTree = ""; 80 | }; 81 | 97C146E51CF9000F007C117D = { 82 | isa = PBXGroup; 83 | children = ( 84 | 9740EEB11CF90186004384FC /* Flutter */, 85 | 97C146F01CF9000F007C117D /* Runner */, 86 | 97C146EF1CF9000F007C117D /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 97C146EF1CF9000F007C117D /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 97C146EE1CF9000F007C117D /* Runner.app */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 97C146F01CF9000F007C117D /* Runner */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 102 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 103 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 104 | 97C147021CF9000F007C117D /* Info.plist */, 105 | 97C146F11CF9000F007C117D /* Supporting Files */, 106 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 107 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 108 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 109 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 110 | ); 111 | path = Runner; 112 | sourceTree = ""; 113 | }; 114 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | ); 118 | name = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | 97C146ED1CF9000F007C117D /* Runner */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 127 | buildPhases = ( 128 | 9740EEB61CF901F6004384FC /* Run Script */, 129 | 97C146EA1CF9000F007C117D /* Sources */, 130 | 97C146EB1CF9000F007C117D /* Frameworks */, 131 | 97C146EC1CF9000F007C117D /* Resources */, 132 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 133 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 134 | ); 135 | buildRules = ( 136 | ); 137 | dependencies = ( 138 | ); 139 | name = Runner; 140 | productName = Runner; 141 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 142 | productType = "com.apple.product-type.application"; 143 | }; 144 | /* End PBXNativeTarget section */ 145 | 146 | /* Begin PBXProject section */ 147 | 97C146E61CF9000F007C117D /* Project object */ = { 148 | isa = PBXProject; 149 | attributes = { 150 | LastUpgradeCheck = 1020; 151 | ORGANIZATIONNAME = "The Chromium Authors"; 152 | TargetAttributes = { 153 | 97C146ED1CF9000F007C117D = { 154 | CreatedOnToolsVersion = 7.3.1; 155 | LastSwiftMigration = 1100; 156 | }; 157 | }; 158 | }; 159 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = en; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | Base, 166 | ); 167 | mainGroup = 97C146E51CF9000F007C117D; 168 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 169 | projectDirPath = ""; 170 | projectRoot = ""; 171 | targets = ( 172 | 97C146ED1CF9000F007C117D /* Runner */, 173 | ); 174 | }; 175 | /* End PBXProject section */ 176 | 177 | /* Begin PBXResourcesBuildPhase section */ 178 | 97C146EC1CF9000F007C117D /* Resources */ = { 179 | isa = PBXResourcesBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 183 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 184 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 185 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXResourcesBuildPhase section */ 190 | 191 | /* Begin PBXShellScriptBuildPhase section */ 192 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 193 | isa = PBXShellScriptBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | ); 197 | inputPaths = ( 198 | ); 199 | name = "Thin Binary"; 200 | outputPaths = ( 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | shellPath = /bin/sh; 204 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 205 | }; 206 | 9740EEB61CF901F6004384FC /* Run Script */ = { 207 | isa = PBXShellScriptBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | ); 211 | inputPaths = ( 212 | ); 213 | name = "Run Script"; 214 | outputPaths = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | shellPath = /bin/sh; 218 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 219 | }; 220 | /* End PBXShellScriptBuildPhase section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | 97C146EA1CF9000F007C117D /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 228 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin PBXVariantGroup section */ 235 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | 97C146FB1CF9000F007C117D /* Base */, 239 | ); 240 | name = Main.storyboard; 241 | sourceTree = ""; 242 | }; 243 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 244 | isa = PBXVariantGroup; 245 | children = ( 246 | 97C147001CF9000F007C117D /* Base */, 247 | ); 248 | name = LaunchScreen.storyboard; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXVariantGroup section */ 252 | 253 | /* Begin XCBuildConfiguration section */ 254 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 255 | isa = XCBuildConfiguration; 256 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_ANALYZER_NONNULL = YES; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_COMMA = YES; 267 | CLANG_WARN_CONSTANT_CONVERSION = YES; 268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_EMPTY_BODY = YES; 271 | CLANG_WARN_ENUM_CONVERSION = YES; 272 | CLANG_WARN_INFINITE_RECURSION = YES; 273 | CLANG_WARN_INT_CONVERSION = YES; 274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 279 | CLANG_WARN_STRICT_PROTOTYPES = YES; 280 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 286 | ENABLE_NS_ASSERTIONS = NO; 287 | ENABLE_STRICT_OBJC_MSGSEND = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 297 | MTL_ENABLE_DEBUG_INFO = NO; 298 | SDKROOT = iphoneos; 299 | SUPPORTED_PLATFORMS = iphoneos; 300 | TARGETED_DEVICE_FAMILY = "1,2"; 301 | VALIDATE_PRODUCT = YES; 302 | }; 303 | name = Profile; 304 | }; 305 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 306 | isa = XCBuildConfiguration; 307 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 308 | buildSettings = { 309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 310 | CLANG_ENABLE_MODULES = YES; 311 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 312 | ENABLE_BITCODE = NO; 313 | FRAMEWORK_SEARCH_PATHS = ( 314 | "$(inherited)", 315 | "$(PROJECT_DIR)/Flutter", 316 | ); 317 | INFOPLIST_FILE = Runner/Info.plist; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 319 | LIBRARY_SEARCH_PATHS = ( 320 | "$(inherited)", 321 | "$(PROJECT_DIR)/Flutter", 322 | ); 323 | PRODUCT_BUNDLE_IDENTIFIER = com.duet.rescore; 324 | PRODUCT_NAME = "$(TARGET_NAME)"; 325 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 326 | SWIFT_VERSION = 5.0; 327 | VERSIONING_SYSTEM = "apple-generic"; 328 | }; 329 | name = Profile; 330 | }; 331 | 97C147031CF9000F007C117D /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 334 | buildSettings = { 335 | ALWAYS_SEARCH_USER_PATHS = NO; 336 | CLANG_ANALYZER_NONNULL = YES; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 342 | CLANG_WARN_BOOL_CONVERSION = YES; 343 | CLANG_WARN_COMMA = YES; 344 | CLANG_WARN_CONSTANT_CONVERSION = YES; 345 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 347 | CLANG_WARN_EMPTY_BODY = YES; 348 | CLANG_WARN_ENUM_CONVERSION = YES; 349 | CLANG_WARN_INFINITE_RECURSION = YES; 350 | CLANG_WARN_INT_CONVERSION = YES; 351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 356 | CLANG_WARN_STRICT_PROTOTYPES = YES; 357 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 358 | CLANG_WARN_UNREACHABLE_CODE = YES; 359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 360 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 361 | COPY_PHASE_STRIP = NO; 362 | DEBUG_INFORMATION_FORMAT = dwarf; 363 | ENABLE_STRICT_OBJC_MSGSEND = YES; 364 | ENABLE_TESTABILITY = YES; 365 | GCC_C_LANGUAGE_STANDARD = gnu99; 366 | GCC_DYNAMIC_NO_PIC = NO; 367 | GCC_NO_COMMON_BLOCKS = YES; 368 | GCC_OPTIMIZATION_LEVEL = 0; 369 | GCC_PREPROCESSOR_DEFINITIONS = ( 370 | "DEBUG=1", 371 | "$(inherited)", 372 | ); 373 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 374 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 375 | GCC_WARN_UNDECLARED_SELECTOR = YES; 376 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 377 | GCC_WARN_UNUSED_FUNCTION = YES; 378 | GCC_WARN_UNUSED_VARIABLE = YES; 379 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 380 | MTL_ENABLE_DEBUG_INFO = YES; 381 | ONLY_ACTIVE_ARCH = YES; 382 | SDKROOT = iphoneos; 383 | TARGETED_DEVICE_FAMILY = "1,2"; 384 | }; 385 | name = Debug; 386 | }; 387 | 97C147041CF9000F007C117D /* Release */ = { 388 | isa = XCBuildConfiguration; 389 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 390 | buildSettings = { 391 | ALWAYS_SEARCH_USER_PATHS = NO; 392 | CLANG_ANALYZER_NONNULL = YES; 393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 394 | CLANG_CXX_LIBRARY = "libc++"; 395 | CLANG_ENABLE_MODULES = YES; 396 | CLANG_ENABLE_OBJC_ARC = YES; 397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 398 | CLANG_WARN_BOOL_CONVERSION = YES; 399 | CLANG_WARN_COMMA = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_EMPTY_BODY = YES; 404 | CLANG_WARN_ENUM_CONVERSION = YES; 405 | CLANG_WARN_INFINITE_RECURSION = YES; 406 | CLANG_WARN_INT_CONVERSION = YES; 407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 412 | CLANG_WARN_STRICT_PROTOTYPES = YES; 413 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 417 | COPY_PHASE_STRIP = NO; 418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 419 | ENABLE_NS_ASSERTIONS = NO; 420 | ENABLE_STRICT_OBJC_MSGSEND = YES; 421 | GCC_C_LANGUAGE_STANDARD = gnu99; 422 | GCC_NO_COMMON_BLOCKS = YES; 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNDECLARED_SELECTOR = YES; 426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 427 | GCC_WARN_UNUSED_FUNCTION = YES; 428 | GCC_WARN_UNUSED_VARIABLE = YES; 429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 430 | MTL_ENABLE_DEBUG_INFO = NO; 431 | SDKROOT = iphoneos; 432 | SUPPORTED_PLATFORMS = iphoneos; 433 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 434 | TARGETED_DEVICE_FAMILY = "1,2"; 435 | VALIDATE_PRODUCT = YES; 436 | }; 437 | name = Release; 438 | }; 439 | 97C147061CF9000F007C117D /* Debug */ = { 440 | isa = XCBuildConfiguration; 441 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 442 | buildSettings = { 443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 444 | CLANG_ENABLE_MODULES = YES; 445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 446 | ENABLE_BITCODE = NO; 447 | FRAMEWORK_SEARCH_PATHS = ( 448 | "$(inherited)", 449 | "$(PROJECT_DIR)/Flutter", 450 | ); 451 | INFOPLIST_FILE = Runner/Info.plist; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | LIBRARY_SEARCH_PATHS = ( 454 | "$(inherited)", 455 | "$(PROJECT_DIR)/Flutter", 456 | ); 457 | PRODUCT_BUNDLE_IDENTIFIER = com.duet.rescore; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 461 | SWIFT_VERSION = 5.0; 462 | VERSIONING_SYSTEM = "apple-generic"; 463 | }; 464 | name = Debug; 465 | }; 466 | 97C147071CF9000F007C117D /* Release */ = { 467 | isa = XCBuildConfiguration; 468 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 469 | buildSettings = { 470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 471 | CLANG_ENABLE_MODULES = YES; 472 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 473 | ENABLE_BITCODE = NO; 474 | FRAMEWORK_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "$(PROJECT_DIR)/Flutter", 477 | ); 478 | INFOPLIST_FILE = Runner/Info.plist; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 480 | LIBRARY_SEARCH_PATHS = ( 481 | "$(inherited)", 482 | "$(PROJECT_DIR)/Flutter", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = com.duet.rescore; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 487 | SWIFT_VERSION = 5.0; 488 | VERSIONING_SYSTEM = "apple-generic"; 489 | }; 490 | name = Release; 491 | }; 492 | /* End XCBuildConfiguration section */ 493 | 494 | /* Begin XCConfigurationList section */ 495 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 496 | isa = XCConfigurationList; 497 | buildConfigurations = ( 498 | 97C147031CF9000F007C117D /* Debug */, 499 | 97C147041CF9000F007C117D /* Release */, 500 | 249021D3217E4FDB00AE95B9 /* Profile */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | 97C147061CF9000F007C117D /* Debug */, 509 | 97C147071CF9000F007C117D /* Release */, 510 | 249021D4217E4FDB00AE95B9 /* Profile */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | /* End XCConfigurationList section */ 516 | }; 517 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 518 | } 519 | --------------------------------------------------------------------------------