diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 45325b8e..b24aba01 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -7,7 +7,7 @@ on: push: branches: [main] pull_request: - branches: [main, ffi-wrapper, ffi-wrapper-core-pkg] + branches: [main, ffi-wrapper, ffi-wrapper-text-pkg] workflow_dispatch: schedule: - cron: "0 0 * * *" # Every day at midnight @@ -25,7 +25,9 @@ jobs: strategy: fail-fast: false matrix: - flutter_version: [stable, beta, master] + flutter_version: [master] + # TODO(craiglabenz): reverse once CI works + # flutter_version: [stable, beta, master] # TODO(craiglabenz): Add `ubuntu-latest` and `windows-latest` when those artifacts exist os: [macos-latest] steps: diff --git a/Makefile b/Makefile index b89183a7..11478f9c 100644 --- a/Makefile +++ b/Makefile @@ -5,17 +5,25 @@ headers: # Runs `ffigen` for all packages generate: generate_core generate_text -# Runs `ffigen` for all packages, compiles the faked C artifacts, and runs all tests +# Runs `ffigen` for all packages and runs all tests test: generate_text test_text generate_core test_core -# Runs `ffigen` for all packages and all tests for all packages +# Runs all tests for all packages test_only: test_core test_text # Rebuilds the MediaPipe task for macOS # Assumes google/mediapipe and google/flutter-mediapipe are siblings on the file system -compile_text_classifier_macos: +compile_text_classifier_macos_arm: cd ../mediapipe && bazel build --linkopt -s --config darwin_arm64 --strip always --define MEDIAPIPE_DISABLE_GPU=1 mediapipe/tasks/c/text/text_classifier:libtext_classifier.dylib - cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets + cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets/libtext_classifier_arm64.dylib + +compile_text_classifier_macos_x86: + cd ../mediapipe && bazel build --linkopt -s --config darwin_x86_64 --strip always --define MEDIAPIPE_DISABLE_GPU=1 mediapipe/tasks/c/text/text_classifier:libtext_classifier.dylib + cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets/libtext_classifier_x64.dylib + +# Runs `sdks_finder` to update manifest files +sdks: + dart tool/builder/bin/main.dart sdks # Core --- @@ -33,9 +41,10 @@ test_core: generate_text: cd packages/mediapipe-task-text && dart --enable-experiment=native-assets run ffigen --config=ffigen.yaml -# Runs `ffigen` for `mediapipe_text` and all text tests -test_text: compile_fake_text test_text_only - # Runs all text tests -test_text_only: +test_text: cd packages/mediapipe-task-text && flutter test + cd packages/mediapipe-task-text/example && flutter test + +example_text: + cd packages/mediapipe-task-text/example && flutter run -d macos \ No newline at end of file diff --git a/README.md b/README.md index 16bbaad8..817b5d83 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # Flutter-MediaPipe This repository will be home to the source code for the mediapipe_task_vision, mediapipe_task_audio, and mediapipe_task_text plugins for Flutter. + +## Releasing + +### Updating MediaPipe SDKs + +Anytime MediaPipe releases new versions of their SDKs, this package will need to be updated to incorporate those latest builds. SDK versions are pinned in the `sdk_downloads.json` files in each package, which are updated by running the following command from the root of the repository: + +``` +$ make sdks +``` + +The Google Cloud Storage bucket in question only gives read-list access to a specific list of Googlers' accounts, so this command must be run from such a Googler's corp machines. + +After this, create and merge a PR with the changes and then proceed to `Releasing to pub.dev`. + +### Releasing to pub.dev + +TODO \ No newline at end of file diff --git a/packages/mediapipe-core/lib/generated/core_symbols.yaml b/packages/mediapipe-core/lib/generated/core_symbols.yaml index 95f3c222..1865306f 100644 --- a/packages/mediapipe-core/lib/generated/core_symbols.yaml +++ b/packages/mediapipe-core/lib/generated/core_symbols.yaml @@ -6,6 +6,8 @@ files: symbols: c:@S@BaseOptions: name: BaseOptions + c:@S@Categories: + name: Categories c:@S@Category: name: Category c:@S@ClassificationResult: diff --git a/packages/mediapipe-core/lib/src/containers.dart b/packages/mediapipe-core/lib/src/containers.dart index 5111040b..cf789fa3 100644 --- a/packages/mediapipe-core/lib/src/containers.dart +++ b/packages/mediapipe-core/lib/src/containers.dart @@ -40,19 +40,19 @@ class Category { /// Accepts a pointer to a list of structs, and a count representing the length /// of the list, and returns a list of pure-Dart [Category] instances. - static List fromStructs( + static List structsToDart( Pointer structs, int count, ) { final categories = []; for (int i = 0; i < count; i++) { - categories.add(fromStruct(structs[i])); + categories.add(structToDart(structs[i])); } return categories; } /// Accepts a pointer to a single struct and returns a pure-Dart [Category] instance. - static Category fromStruct(bindings.Category struct) { + static Category structToDart(bindings.Category struct) { return Category( index: struct.index, score: struct.score, @@ -62,19 +62,25 @@ class Category { } /// Releases all C memory associated with a list of [bindings.Category] pointers. - /// This method is important to call after calling [Category.fromStructs] to + /// This method is important to call after calling [Category.structsToDart] to /// convert that C memory into pure-Dart objects. static void freeStructs(Pointer structs, int count) { int index = 0; while (index < count) { bindings.Category obj = structs[index]; - calloc.free(obj.category_name); - calloc.free(obj.display_name); + Category.freeStruct(obj); index++; } calloc.free(structs); } + /// Releases the string fields associated with a single [bindings.Category] + /// struct. + static void freeStruct(bindings.Category struct) { + calloc.free(struct.category_name); + calloc.free(struct.display_name); + } + @override String toString() => 'Category(index=$index, score=$score, ' 'categoryName=$categoryName, displayName=$displayName)'; @@ -108,22 +114,22 @@ class Classifications { /// Accepts a pointer to a list of structs, and a count representing the length /// of the list, and returns a list of pure-Dart [Classifications] instances. - static List fromStructs( + static List structsToDart( Pointer structs, int count, ) { final classifications = []; for (int i = 0; i < count; i++) { - classifications.add(fromStruct(structs[i])); + classifications.add(structToDart(structs[i])); } return classifications; } /// Accepts a pointer to a single struct and returns a pure-Dart [Classifications] /// instance. - static Classifications fromStruct(bindings.Classifications struct) { + static Classifications structToDart(bindings.Classifications struct) { return Classifications( - categories: Category.fromStructs( + categories: Category.structsToDart( struct.categories, struct.categories_count, ), @@ -133,7 +139,7 @@ class Classifications { } /// Releases all C memory associated with a list of [bindings.Classifications] - /// pointers. This method is important to call after calling [Classifications.fromStructs] + /// pointers. This method is important to call after calling [Classifications.structsToDart] /// to convert that C memory into pure-Dart objects. static void freeStructs( Pointer structs, diff --git a/packages/mediapipe-core/lib/src/task_options.dart b/packages/mediapipe-core/lib/src/task_options.dart index c0f6fa7b..b1a97595 100644 --- a/packages/mediapipe-core/lib/src/task_options.dart +++ b/packages/mediapipe-core/lib/src/task_options.dart @@ -21,15 +21,40 @@ import 'third_party/mediapipe/generated/mediapipe_common_bindings.dart' /// classifier's desired behavior. class BaseOptions extends Equatable { /// Generative constructor that creates a [BaseOptions] instance. - const BaseOptions({this.modelAssetBuffer, this.modelAssetPath}) - : assert( + const BaseOptions._({ + this.modelAssetBuffer, + this.modelAssetPath, + required _BaseOptionsType type, + }) : assert( !(modelAssetBuffer == null && modelAssetPath == null), 'You must supply either `modelAssetBuffer` or `modelAssetPath`', ), assert( !(modelAssetBuffer != null && modelAssetPath != null), 'You must only supply one of `modelAssetBuffer` and `modelAssetPath`', - ); + ), + _type = type; + + /// Constructor for [BaseOptions] classes using a file system path. + /// + /// In practice, this is unsupported, as assets in Flutter are bundled into + /// the build output and not available on disk. However, it can potentially + /// be helpful for testing / development purposes. + factory BaseOptions.path(String path) => BaseOptions._( + modelAssetPath: path, + type: _BaseOptionsType.path, + ); + + /// Constructor for [BaseOptions] classes using an in-memory pointer to the + /// MediaPipe SDK. + /// + /// In practice, this is the only option supported for production builds. + factory BaseOptions.memory(Uint8List buffer) { + return BaseOptions._( + modelAssetBuffer: buffer, + type: _BaseOptionsType.memory, + ); + } /// The model asset file contents as bytes; final Uint8List? modelAssetBuffer; @@ -37,35 +62,48 @@ class BaseOptions extends Equatable { /// Path to the model asset file. final String? modelAssetPath; + final _BaseOptionsType _type; + /// Converts this pure-Dart representation into C-memory suitable for the /// MediaPipe SDK to instantiate various classifiers. Pointer toStruct() { final struct = calloc(); - if (modelAssetPath != null) { - struct.ref.model_asset_path = prepareString(modelAssetPath!); - } - if (modelAssetBuffer != null) { - struct.ref.model_asset_buffer = prepareUint8List(modelAssetBuffer!); - struct.ref.model_asset_buffer_count = modelAssetBuffer!.lengthInBytes; + switch (_type) { + case _BaseOptionsType.path: + { + struct.ref.model_asset_path = prepareString(modelAssetPath!); + } + case _BaseOptionsType.memory: + { + struct.ref.model_asset_buffer = prepareUint8List(modelAssetBuffer!); + struct.ref.model_asset_buffer_count = modelAssetBuffer!.lengthInBytes; + } } + return struct; } - @override - List get props => [modelAssetBuffer, modelAssetPath]; - /// Releases all C memory held by this [bindings.BaseOptions] struct. static void freeStruct(bindings.BaseOptions struct) { - if (struct.model_asset_buffer.address != 0) { - calloc.free(struct.model_asset_buffer); - } - if (struct.model_asset_path.address != 0) { + if (struct.model_asset_path.isNotNullPointer) { calloc.free(struct.model_asset_path); } + if (struct.model_asset_buffer.isNotNullPointer) { + calloc.free(struct.model_asset_buffer); + } } + + @override + List get props => [ + modelAssetBuffer, + modelAssetPath, + modelAssetBuffer?.lengthInBytes, + ]; } +enum _BaseOptionsType { path, memory } + /// Dart representation of MediaPipe's "ClassifierOptions" concept. /// /// Classifier options shared across MediaPipe classification tasks. diff --git a/packages/mediapipe-core/lib/src/test_utils.dart b/packages/mediapipe-core/lib/src/test_utils.dart new file mode 100644 index 00000000..ae5ab9af --- /dev/null +++ b/packages/mediapipe-core/lib/src/test_utils.dart @@ -0,0 +1,54 @@ +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; + +import 'package:mediapipe_core/mediapipe_core.dart'; +import 'package:mediapipe_core/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart' + as core_bindings; + +/// Hydrates a faked [core_bindings.Category] object. +void populateCategory( + core_bindings.Category category, { + int index = 1, + double score = 0.9, + String? categoryName = 'Positive', + String? displayName, +}) { + category.index = index; + category.score = score; + + if (categoryName != null) { + category.category_name = prepareString(categoryName); + } + if (displayName != null) { + category.display_name = prepareString(displayName); + } +} + +/// Hydrates a faked [core_bindings.Classifications] object. +/// +/// If [categories] is passed, [numCategories] must indicate its length; +/// otherwise, this function generates [numCategories] faked +/// [core_bindings.Category] objects. +void populateClassifications( + core_bindings.Classifications classifications, { + Pointer? categories, + int numCategories = 2, + int headIndex = 1, + String headName = 'Head', +}) { + if (isNotNullOrNullPointer(categories)) { + classifications.categories = categories!; + classifications.categories_count = numCategories; + } else { + final ptrs = calloc(numCategories); + int count = 0; + while (count < numCategories) { + populateCategory(ptrs[count]); + count++; + } + classifications.categories = ptrs; + classifications.categories_count = numCategories; + } + classifications.head_name = prepareString(headName); + classifications.head_index = headIndex; +} diff --git a/packages/mediapipe-core/lib/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart b/packages/mediapipe-core/lib/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart index f6217336..e1893d44 100644 --- a/packages/mediapipe-core/lib/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart +++ b/packages/mediapipe-core/lib/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart @@ -22,10 +22,10 @@ import 'dart:ffi' as ffi; final class BaseOptions extends ffi.Struct { external ffi.Pointer model_asset_buffer; - external ffi.Pointer model_asset_path; - @ffi.UnsignedInt() external int model_asset_buffer_count; + + external ffi.Pointer model_asset_path; } final class __mbstate_t extends ffi.Union { @@ -152,6 +152,13 @@ final class Category extends ffi.Struct { external ffi.Pointer display_name; } +final class Categories extends ffi.Struct { + external ffi.Pointer categories; + + @ffi.Uint32() + external int categories_count; +} + final class Classifications extends ffi.Struct { external ffi.Pointer categories; diff --git a/packages/mediapipe-core/test/containers_test.dart b/packages/mediapipe-core/test/containers_test.dart new file mode 100644 index 00000000..1baecdc7 --- /dev/null +++ b/packages/mediapipe-core/test/containers_test.dart @@ -0,0 +1,114 @@ +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; +import 'package:mediapipe_core/mediapipe_core.dart'; +import 'package:mediapipe_core/src/test_utils.dart'; +import 'package:test/test.dart'; +import 'package:mediapipe_core/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart' + as core_bindings; + +void main() { + group('Category.structToDart should', () { + test('load a Category', () { + final categoryPtr = calloc(); + populateCategory(categoryPtr.ref); + + final category = Category.structToDart(categoryPtr.ref); + expect(category.index, 1); + expect(category.categoryName, 'Positive'); + expect(category.displayName, isNull); + expect(category.score, closeTo(0.9, 0.0001)); + Category.freeStruct(categoryPtr.ref); + calloc.free(categoryPtr); + }); + + test('load a Category with a display name', () { + final categoryPtr = calloc(); + populateCategory(categoryPtr.ref, displayName: 'v-good'); + + final category = Category.structToDart(categoryPtr.ref); + expect(category.index, 1); + expect(category.categoryName, 'Positive'); + expect(category.displayName, 'v-good'); + expect(category.score, closeTo(0.9, 0.0001)); + Category.freeStruct(categoryPtr.ref); + calloc.free(categoryPtr); + }); + + test('load a Category with no names', () { + final categoryPtr = calloc(); + populateCategory(categoryPtr.ref, categoryName: null); + + final category = Category.structToDart(categoryPtr.ref); + expect(category.index, 1); + expect(category.categoryName, isNull); + expect(category.displayName, isNull); + expect(category.score, closeTo(0.9, 0.0001)); + Category.freeStruct(categoryPtr.ref); + calloc.free(categoryPtr); + }); + + test('should load a list of structs', () { + final ptrs = calloc(2); + populateCategory(ptrs[0]); + populateCategory( + ptrs[1], + categoryName: 'Negative', + index: 2, + score: 0.01, + ); + final categories = Category.structsToDart(ptrs, 2); + expect(categories, hasLength(2)); + expect(categories[0].categoryName, 'Positive'); + expect(categories[0].index, 1); + expect(categories[0].score, closeTo(0.9, 0.0001)); + + expect(categories[1].categoryName, 'Negative'); + expect(categories[1].index, 2); + expect(categories[1].score, closeTo(0.01, 0.0001)); + }); + }); + + group('Classifications.structToDart should', () { + test('load a Classifications object', () { + final classificationsPtr = calloc(); + populateClassifications(classificationsPtr.ref); + + final classifications = + Classifications.structToDart(classificationsPtr.ref); + expect(classifications.headIndex, 1); + expect(classifications.headName, 'Head'); + expect(classifications.categories.length, 2); + expect(classifications.categories.first.categoryName, 'Positive'); + expect(classifications.categories.last.categoryName, 'Positive'); + + Classifications.freeStructs(classificationsPtr, 1); + }); + + test('load a Classifications object with 1 category', () { + final classificationsPtr = calloc(); + populateClassifications(classificationsPtr.ref, numCategories: 1); + + final classifications = + Classifications.structToDart(classificationsPtr.ref); + expect(classifications.headIndex, 1); + expect(classifications.headName, 'Head'); + expect(classifications.categories.length, 1); + expect(classifications.categories.first.categoryName, 'Positive'); + + Classifications.freeStructs(classificationsPtr, 1); + }); + + test('load a Classifications object with no categories', () { + final classificationsPtr = calloc(); + populateClassifications(classificationsPtr.ref, numCategories: 0); + + final classifications = + Classifications.structToDart(classificationsPtr.ref); + expect(classifications.headIndex, 1); + expect(classifications.headName, 'Head'); + expect(classifications.categories.length, 0); + + Classifications.freeStructs(classificationsPtr, 1); + }); + }); +} diff --git a/packages/mediapipe-core/test/task_options_test.dart b/packages/mediapipe-core/test/task_options_test.dart index 143a9ff4..43037acd 100644 --- a/packages/mediapipe-core/test/task_options_test.dart +++ b/packages/mediapipe-core/test/task_options_test.dart @@ -9,32 +9,16 @@ import 'package:test/test.dart'; import 'package:mediapipe_core/mediapipe_core.dart'; void main() { - group('BaseOptions constructor should', () { - test('enforce exactly one of modelPath and modelBuffer', () { - expect( - () => BaseOptions( - modelAssetPath: 'abc', - modelAssetBuffer: Uint8List.fromList([1, 2, 3]), - ), - throwsA(TypeMatcher()), - ); - - expect(BaseOptions.new, throwsA(TypeMatcher())); - }); - }); - - group('BaseOptions.toStruct/fromStruct should', () { + group('BaseOptions.toStruct/structToDart should', () { test('allocate memory in C for a modelAssetPath', () { - final options = BaseOptions(modelAssetPath: 'abc'); + final options = BaseOptions.path('abc'); final struct = options.toStruct(); expect(toDartString(struct.ref.model_asset_path), 'abc'); expectNullPtr(struct.ref.model_asset_buffer); }); test('allocate memory in C for a modelAssetBuffer', () { - final options = BaseOptions( - modelAssetBuffer: Uint8List.fromList([1, 2, 3]), - ); + final options = BaseOptions.memory(Uint8List.fromList([1, 2, 3])); final struct = options.toStruct(); expect( toUint8List(struct.ref.model_asset_buffer), @@ -44,9 +28,7 @@ void main() { }); test('allocate memory in C for a modelAssetBuffer containing 0', () { - final options = BaseOptions( - modelAssetBuffer: Uint8List.fromList([1, 2, 0, 3]), - ); + final options = BaseOptions.memory(Uint8List.fromList([1, 2, 0, 3])); final struct = options.toStruct(); expect( toUint8List(struct.ref.model_asset_buffer), diff --git a/packages/mediapipe-core/third_party/mediapipe/tasks/c/components/containers/category.h b/packages/mediapipe-core/third_party/mediapipe/tasks/c/components/containers/category.h index 9a47815a..03383116 100644 --- a/packages/mediapipe-core/third_party/mediapipe/tasks/c/components/containers/category.h +++ b/packages/mediapipe-core/third_party/mediapipe/tasks/c/components/containers/category.h @@ -16,6 +16,8 @@ limitations under the License. #ifndef MEDIAPIPE_TASKS_C_COMPONENTS_CONTAINERS_CATEGORY_H_ #define MEDIAPIPE_TASKS_C_COMPONENTS_CONTAINERS_CATEGORY_H_ +#include + #ifdef __cplusplus extern "C" { #endif @@ -43,6 +45,12 @@ struct Category { char* display_name; }; +// A list of categories. +struct Categories { + struct Category* categories; + uint32_t categories_count; +}; + #ifdef __cplusplus } // extern C #endif diff --git a/packages/mediapipe-core/third_party/mediapipe/tasks/c/core/base_options.h b/packages/mediapipe-core/third_party/mediapipe/tasks/c/core/base_options.h index 6bd4d6e2..20c068a8 100644 --- a/packages/mediapipe-core/third_party/mediapipe/tasks/c/core/base_options.h +++ b/packages/mediapipe-core/third_party/mediapipe/tasks/c/core/base_options.h @@ -20,17 +20,17 @@ limitations under the License. extern "C" { #endif - // Base options for MediaPipe C Tasks. - struct BaseOptions { - // The model asset file contents as a string. - const char* model_asset_buffer; +// Base options for MediaPipe C Tasks. +struct BaseOptions { + // The model asset file contents as bytes. + const char* model_asset_buffer; - // The path to the model asset to open and mmap in memory. - const char* model_asset_path; + // The size of the model assets buffer (or `0` if not set). + unsigned int model_asset_buffer_count; - // The size of the model assets buffer (or `0` if not set). - unsigned int model_asset_buffer_count; - }; + // The path to the model asset to open and mmap in memory. + const char* model_asset_path; +}; #ifdef __cplusplus } // extern C diff --git a/packages/mediapipe-task-audio/sdk_downloads.dart b/packages/mediapipe-task-audio/sdk_downloads.dart new file mode 100644 index 00000000..1f0512e2 --- /dev/null +++ b/packages/mediapipe-task-audio/sdk_downloads.dart @@ -0,0 +1,2 @@ +// Generated file. Do not manually edit. +final Map> sdkDownloadUrls = {}; diff --git a/packages/mediapipe-task-text/build.dart b/packages/mediapipe-task-text/build.dart new file mode 100644 index 00000000..fa52220c --- /dev/null +++ b/packages/mediapipe-task-text/build.dart @@ -0,0 +1,96 @@ +import 'dart:io'; +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; + +import 'sdk_downloads.dart'; + +late File logFile; + +final logs = <(DateTime, String)>[]; +void log(String msg) { + logs.add((DateTime.now(), msg)); + if (!logFile.parent.existsSync()) { + logFile.parent.createSync(); + } + + if (logFile.existsSync()) { + logFile.deleteSync(); + } + logFile.createSync(); + logFile.writeAsStringSync(logs + .map((rec) => '[${rec.$1.toIso8601String()}] ${rec.$2}') + .toList() + .join('\n\n')); +} + +Future main(List args) async { + logFile = File( + path.joinAll([ + Directory.current.path, // root dir of app using `mediapipe-task-xyz` + 'build/${DateTime.now().millisecondsSinceEpoch}-build-log.txt', + ]), + ); + + log(args.join(' ')); + final buildConfig = await BuildConfig.fromArgs(args); + final String targetOs = buildConfig.targetOs.toString(); + + log('dir.current: ${Directory.current.absolute.path}'); + + // Throw if target runtime is unsupported. + if (!sdkDownloadUrls.containsKey(targetOs)) { + throw Exception('Unsupported target OS: $targetOs. ' + 'Supported values are: ${sdkDownloadUrls.keys.toSet()}'); + } + + final buildOutput = BuildOutput(); + buildOutput.dependencies.dependencies + .add(buildConfig.packageRoot.resolve('build.dart')); + buildOutput.dependencies.dependencies + .add(buildConfig.packageRoot.resolve('sdk_downloads.dart')); + + final archKeys = sdkDownloadUrls[targetOs]!.keys; + for (final String arch in archKeys) { + final assetUrl = sdkDownloadUrls[targetOs]![arch]!; + final downloadFileLocation = + buildConfig.outDir.resolve('${arch}_${assetUrl.split('/').last}'); + log('downloadFileLocation: $downloadFileLocation'); + buildOutput.assets.add( + Asset( + id: 'package:mediapipe_text/src/third_party/mediapipe/generated/mediapipe_text_bindings.dart', + linkMode: LinkMode.dynamic, + target: Target.fromArchitectureAndOs( + Architecture.fromString(arch), buildConfig.targetOs), + path: AssetAbsolutePath(downloadFileLocation), + ), + ); + if (!buildConfig.dryRun) { + downloadAsset(assetUrl, downloadFileLocation); + } + } + + await buildOutput.writeToFile(outDir: buildConfig.outDir); +} + +Future downloadAsset(String assetUrl, Uri destinationFile) async { + final downloadUri = Uri.parse(assetUrl); + final downloadedFile = File(destinationFile.toFilePath()); + print('Saving file to ${downloadedFile.absolute.path}'); + + final downloadResponse = await http.get(downloadUri); + log('Download response: ${downloadResponse.statusCode}'); + + if (downloadResponse.statusCode == 200) { + if (downloadedFile.existsSync()) { + downloadedFile.deleteSync(); + } + downloadedFile.createSync(); + log('Saving file to ${downloadedFile.absolute.path}'); + downloadedFile.writeAsBytes(downloadResponse.bodyBytes); + } else { + log('${downloadResponse.statusCode} :: ${downloadResponse.body}'); + throw Exception( + '${downloadResponse.statusCode} :: ${downloadResponse.body}'); + } +} diff --git a/packages/mediapipe-task-text/dart_test.yaml b/packages/mediapipe-task-text/dart_test.yaml new file mode 100644 index 00000000..2cecf55e --- /dev/null +++ b/packages/mediapipe-task-text/dart_test.yaml @@ -0,0 +1,3 @@ +tags: + # Integration tests that talk to C code bundled via the native-assets feature + native-assets: diff --git a/packages/mediapipe-task-text/example/.gitignore b/packages/mediapipe-task-text/example/.gitignore new file mode 100644 index 00000000..b49e12fa --- /dev/null +++ b/packages/mediapipe-task-text/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +bert_classifier.tflite \ No newline at end of file diff --git a/packages/mediapipe-task-text/example/.metadata b/packages/mediapipe-task-text/example/.metadata new file mode 100644 index 00000000..767f80e3 --- /dev/null +++ b/packages/mediapipe-task-text/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "995a020e48aa6627ea3f904a59dd56349a819eb4" + channel: "master" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 995a020e48aa6627ea3f904a59dd56349a819eb4 + base_revision: 995a020e48aa6627ea3f904a59dd56349a819eb4 + - platform: android + create_revision: 995a020e48aa6627ea3f904a59dd56349a819eb4 + base_revision: 995a020e48aa6627ea3f904a59dd56349a819eb4 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/mediapipe-task-text/example/README.md b/packages/mediapipe-task-text/example/README.md new file mode 100644 index 00000000..1b7a4e3d --- /dev/null +++ b/packages/mediapipe-task-text/example/README.md @@ -0,0 +1,3 @@ +# example + +A new Flutter project. diff --git a/packages/mediapipe-task-text/example/analysis_options.yaml b/packages/mediapipe-task-text/example/analysis_options.yaml new file mode 100644 index 00000000..f9b30346 --- /dev/null +++ b/packages/mediapipe-task-text/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/packages/mediapipe-task-text/example/android/.gitignore b/packages/mediapipe-task-text/example/android/.gitignore new file mode 100644 index 00000000..6f568019 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/packages/mediapipe-task-text/example/android/app/build.gradle b/packages/mediapipe-task-text/example/android/app/build.gradle new file mode 100644 index 00000000..e28b4e76 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/build.gradle @@ -0,0 +1,67 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.example" + compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies {} diff --git a/packages/mediapipe-task-text/example/android/app/src/debug/AndroidManifest.xml b/packages/mediapipe-task-text/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/main/AndroidManifest.xml b/packages/mediapipe-task-text/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..aff7dec7 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/mediapipe-task-text/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 00000000..70f8f08f --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/mediapipe-task-text/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/drawable/launch_background.xml b/packages/mediapipe-task-text/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/packages/mediapipe-task-text/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/values-night/styles.xml b/packages/mediapipe-task-text/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/main/res/values/styles.xml b/packages/mediapipe-task-text/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/mediapipe-task-text/example/android/app/src/profile/AndroidManifest.xml b/packages/mediapipe-task-text/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/mediapipe-task-text/example/android/build.gradle b/packages/mediapipe-task-text/example/android/build.gradle new file mode 100644 index 00000000..bc157bd1 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/packages/mediapipe-task-text/example/android/gradle.properties b/packages/mediapipe-task-text/example/android/gradle.properties new file mode 100644 index 00000000..598d13fe --- /dev/null +++ b/packages/mediapipe-task-text/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/mediapipe-task-text/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/mediapipe-task-text/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3c472b99 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/packages/mediapipe-task-text/example/android/settings.gradle b/packages/mediapipe-task-text/example/android/settings.gradle new file mode 100644 index 00000000..1d6d19b7 --- /dev/null +++ b/packages/mediapipe-task-text/example/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/packages/mediapipe-task-text/example/ios/.gitignore b/packages/mediapipe-task-text/example/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/mediapipe-task-text/example/ios/Flutter/AppFrameworkInfo.plist b/packages/mediapipe-task-text/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9625e105 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/packages/mediapipe-task-text/example/ios/Flutter/Debug.xcconfig b/packages/mediapipe-task-text/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/mediapipe-task-text/example/ios/Flutter/Release.xcconfig b/packages/mediapipe-task-text/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/mediapipe-task-text/example/ios/Podfile b/packages/mediapipe-task-text/example/ios/Podfile new file mode 100644 index 00000000..fdcc671e --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.pbxproj b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..05db82f9 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,722 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 71879C8BE77D4D5612095357 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEDA1EC44568C4B37A9B3036 /* Pods_RunnerTests.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + CE036829A87D8829E6696512 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3C39DBDCEC441A0FB3A9F6F /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1915FE89322DC8DA9FFBD472 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 251E7F79C4C4F22EC81E392F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 310ACF9BCE8ADE38F76AE396 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 61A51F982B5BB43CCAA4118C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8D741F75DA7F833954FC0919 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ABAE2333F7B8485760E2779F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + BEDA1EC44568C4B37A9B3036 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E3C39DBDCEC441A0FB3A9F6F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CE036829A87D8829E6696512 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF22DC6A7495BDDAB5D66A99 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 71879C8BE77D4D5612095357 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 35C9234736401A2B4BA4E5F1 /* Pods */ = { + isa = PBXGroup; + children = ( + ABAE2333F7B8485760E2779F /* Pods-Runner.debug.xcconfig */, + 1915FE89322DC8DA9FFBD472 /* Pods-Runner.release.xcconfig */, + 61A51F982B5BB43CCAA4118C /* Pods-Runner.profile.xcconfig */, + 310ACF9BCE8ADE38F76AE396 /* Pods-RunnerTests.debug.xcconfig */, + 251E7F79C4C4F22EC81E392F /* Pods-RunnerTests.release.xcconfig */, + 8D741F75DA7F833954FC0919 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 930208CDA6AD96300EFA759A /* Frameworks */ = { + isa = PBXGroup; + children = ( + E3C39DBDCEC441A0FB3A9F6F /* Pods_Runner.framework */, + BEDA1EC44568C4B37A9B3036 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 35C9234736401A2B4BA4E5F1 /* Pods */, + 930208CDA6AD96300EFA759A /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 62FED8461A298492BBA724F2 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + AF22DC6A7495BDDAB5D66A99 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 0D52ECC91CAEA2B20F0D8A4D /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 6F7441E5527CBB4F4A5EC94A /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0D52ECC91CAEA2B20F0D8A4D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 62FED8461A298492BBA724F2 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 6F7441E5527CBB4F4A5EC94A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 310ACF9BCE8ADE38F76AE396 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 251E7F79C4C4F22EC81E392F /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D741F75DA7F833954FC0919 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..87131a09 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner/AppDelegate.swift b/packages/mediapipe-task-text/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..7353c41e Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..6ed2d933 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cd7b009 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..fe730945 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..321773cd Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..502f463a Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..e9f5fea2 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..84ac32ae Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..8953cba0 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..0467bf12 Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/Main.storyboard b/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner/Info.plist b/packages/mediapipe-task-text/example/ios/Runner/Info.plist new file mode 100644 index 00000000..5458fc41 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/mediapipe-task-text/example/ios/Runner/Runner-Bridging-Header.h b/packages/mediapipe-task-text/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/mediapipe-task-text/example/ios/RunnerTests/RunnerTests.swift b/packages/mediapipe-task-text/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/packages/mediapipe-task-text/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/packages/mediapipe-task-text/example/lib/main.dart b/packages/mediapipe-task-text/example/lib/main.dart new file mode 100644 index 00000000..e641a489 --- /dev/null +++ b/packages/mediapipe-task-text/example/lib/main.dart @@ -0,0 +1,136 @@ +import 'dart:io' as io; +import 'dart:typed_data'; +import 'package:logging/logging.dart'; +import 'package:flutter/material.dart'; +import 'package:mediapipe_text/mediapipe_text.dart'; + +final _log = Logger('TextClassificationExample'); + +void main() { + Logger.root.level = Level.FINEST; + Logger.root.onRecord.listen((record) { + io.stdout.writeln('${record.level.name} [${record.loggerName}]' + '[' + '${record.time.hour.toString()}:' + '${record.time.minute.toString().padLeft(2, "0")}:' + '${record.time.second.toString().padLeft(2, "0")}.' + '${record.time.millisecond.toString().padRight(3, "0")}' + '] ${record.message}'); + }); + runApp(const MainApp()); +} + +class MainApp extends StatefulWidget { + const MainApp({super.key}); + + @override + State createState() => _MainAppState(); +} + +class _MainAppState extends State { + late Future _classifier; + + @override + void initState() { + super.initState(); + _classifier = _initClassifier(); + } + + Future _initClassifier() async { + ByteData? classifierBytes = await DefaultAssetBundle.of(context) + .load('assets/bert_classifier.tflite'); + + TextClassifier classifier = TextClassifier( + options: TextClassifierOptions.fromAssetBuffer( + classifierBytes.buffer.asUint8List(), + ), + ); + classifierBytes = null; + return classifier; + } + + @override + Widget build(BuildContext context) => MaterialApp( + home: TextClassificationResults( + classifier: _classifier, + ), + ); +} + +class TextClassificationResults extends StatefulWidget { + const TextClassificationResults({super.key, required this.classifier}); + + final Future classifier; + + @override + State createState() => + _TextClassificationResultsState(); +} + +class _TextClassificationResultsState extends State { + final TextEditingController _controller = TextEditingController(); + List results = []; + String? _isProcessing; + + @override + void initState() { + super.initState(); + _controller.text = 'Hello, world!'; + } + + void _prepareForClassification() { + setState(() { + _isProcessing = _controller.text; + results.add(const CircularProgressIndicator.adaptive()); + }); + } + + void _showClassificationResults(TextClassifierResult classification) { + setState(() { + final categoryName = + classification.firstClassification?.firstCategory?.categoryName; + final score = classification.firstClassification?.firstCategory?.score; + // Replace "..." with the results + final message = '"$_isProcessing" $categoryName :: $score'; + _log.info(message); + results.last = Card( + key: Key('Classification::"$_isProcessing" ${results.length}'), + margin: const EdgeInsets.all(10), + child: Padding( + padding: const EdgeInsets.all(10), + child: Text(message), + ), + ); + _isProcessing = null; + }); + } + + Future _classify() async { + _prepareForClassification(); + BaseTextClassifier classifier = await widget.classifier; + final classification = await classifier.classify(_controller.text); + _showClassificationResults(classification); + } + + @override + Widget build(BuildContext context) => // + Scaffold( + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + TextField(controller: _controller), + ...results, + ], + ), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _isProcessing != null && _controller.text != '' + ? null + : _classify, + child: const Icon(Icons.search), + ), + ); +} diff --git a/packages/mediapipe-task-text/example/macos/.gitignore b/packages/mediapipe-task-text/example/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Debug.xcconfig b/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Release.xcconfig b/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/mediapipe-task-text/example/macos/Podfile b/packages/mediapipe-task-text/example/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.pbxproj b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..3997d94d --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,791 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + D0DDCE128FE337C5B9E9A295 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9935BA9A99DC221620926E9 /* Pods_RunnerTests.framework */; }; + FB57908BE6FAD5004855D15F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B35D5A8F1DC3B3FB038F4B63 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7CFD3790269492C588E2C9DD /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 855B62EE22ED91E4F519EFF9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A9935BA9A99DC221620926E9 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B35D5A8F1DC3B3FB038F4B63 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BA8913FFD9B9350A31F59BD6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + C97F93AAADAA2C44B25186EF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + EB9E9D1C00BE5727AB8A3D85 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F03DADF129363B5D003C7660 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0DDCE128FE337C5B9E9A295 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FB57908BE6FAD5004855D15F /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + C3E7E394D89CFA892EB04DF9 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + C3E7E394D89CFA892EB04DF9 /* Pods */ = { + isa = PBXGroup; + children = ( + F03DADF129363B5D003C7660 /* Pods-Runner.debug.xcconfig */, + C97F93AAADAA2C44B25186EF /* Pods-Runner.release.xcconfig */, + BA8913FFD9B9350A31F59BD6 /* Pods-Runner.profile.xcconfig */, + 855B62EE22ED91E4F519EFF9 /* Pods-RunnerTests.debug.xcconfig */, + EB9E9D1C00BE5727AB8A3D85 /* Pods-RunnerTests.release.xcconfig */, + 7CFD3790269492C588E2C9DD /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + B35D5A8F1DC3B3FB038F4B63 /* Pods_Runner.framework */, + A9935BA9A99DC221620926E9 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + F88EC3E3BF8E6A496380B3C1 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + B400223FD9484ECB1EA04E47 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 3C7112DEBC73266C27DBA095 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 3C7112DEBC73266C27DBA095 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B400223FD9484ECB1EA04E47 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F88EC3E3BF8E6A496380B3C1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 855B62EE22ED91E4F519EFF9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB9E9D1C00BE5727AB8A3D85 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7CFD3790269492C588E2C9DD /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..397f3d33 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner/AppDelegate.swift b/packages/mediapipe-task-text/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/packages/mediapipe-task-text/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/packages/mediapipe-task-text/example/macos/Runner/Base.lproj/MainMenu.xib b/packages/mediapipe-task-text/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner/Configs/AppInfo.xcconfig b/packages/mediapipe-task-text/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..dda192bc --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/packages/mediapipe-task-text/example/macos/Runner/Configs/Debug.xcconfig b/packages/mediapipe-task-text/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/mediapipe-task-text/example/macos/Runner/Configs/Release.xcconfig b/packages/mediapipe-task-text/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/mediapipe-task-text/example/macos/Runner/Configs/Warnings.xcconfig b/packages/mediapipe-task-text/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/packages/mediapipe-task-text/example/macos/Runner/DebugProfile.entitlements b/packages/mediapipe-task-text/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..1c073dbc --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.files.downloads.read-only + + com.apple.security.network.server + + + diff --git a/packages/mediapipe-task-text/example/macos/Runner/Info.plist b/packages/mediapipe-task-text/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/packages/mediapipe-task-text/example/macos/Runner/MainFlutterWindow.swift b/packages/mediapipe-task-text/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/packages/mediapipe-task-text/example/macos/Runner/Release.entitlements b/packages/mediapipe-task-text/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/packages/mediapipe-task-text/example/macos/RunnerTests/RunnerTests.swift b/packages/mediapipe-task-text/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/packages/mediapipe-task-text/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/packages/mediapipe-task-text/example/pubspec.yaml b/packages/mediapipe-task-text/example/pubspec.yaml new file mode 100644 index 00000000..a1f650a0 --- /dev/null +++ b/packages/mediapipe-task-text/example/pubspec.yaml @@ -0,0 +1,29 @@ +name: example +description: A new Flutter project. +publish_to: "none" +version: 0.1.0 + +environment: + sdk: ">=3.1.0 <4.0.0" + +dependencies: + flutter: + sdk: flutter + logging: ^1.2.0 + mediapipe_core: + path: ../../mediapipe-core + mediapipe_text: + path: ../ + path: ^1.8.3 + path_provider: ^2.1.1 + +dev_dependencies: + flutter_lints: ^2.0.0 + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true + + assets: + - assets/bert_classifier.tflite diff --git a/packages/mediapipe-task-text/example/test/widgets_test.dart b/packages/mediapipe-task-text/example/test/widgets_test.dart new file mode 100644 index 00000000..2ed0ef0c --- /dev/null +++ b/packages/mediapipe-task-text/example/test/widgets_test.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mediapipe_core/mediapipe_core.dart'; +import 'package:mediapipe_text/mediapipe_text.dart'; +import 'package:example/main.dart'; + +class FakeTextClassifier extends BaseTextClassifier { + FakeTextClassifier({required super.options}); + + @override + Future classify(String text) => Future.value( + const TextClassifierResult( + classifications: [ + Classifications( + categories: [ + Category( + index: 0, + score: 0.9, + categoryName: 'happy-go-lucky', + displayName: null, + ), + ], + headIndex: 0, + headName: 'whatever', + ), + ], + ), + ); +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + testWidgets('TextClassificationResults should show results', + (WidgetTester tester) async { + final app = MaterialApp( + home: TextClassificationResults( + classifier: Future.value( + FakeTextClassifier( + options: TextClassifierOptions.fromAssetPath('fake'), + ), + ), + ), + ); + + await tester.pumpWidget(app); + await tester.tap(find.byType(Icon)); + await tester.pumpAndSettle(); + expect( + find.byKey(const Key('Classification::"Hello, world!" 1')), + findsOneWidget, + ); + expect( + find.text('"Hello, world!" happy-go-lucky :: 0.9'), + findsOneWidget, + ); + }); +} diff --git a/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_options.dart b/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_options.dart index f7fb7e55..00a76d51 100644 --- a/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_options.dart +++ b/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_options.dart @@ -32,7 +32,7 @@ class TextClassifierOptions { }) { assert(!kIsWeb, 'fromAssetPath cannot be used on the web'); return TextClassifierOptions( - baseOptions: BaseOptions(modelAssetPath: assetPath), + baseOptions: BaseOptions.path(assetPath), classifierOptions: classifierOptions, ); } @@ -45,7 +45,7 @@ class TextClassifierOptions { ClassifierOptions classifierOptions = const ClassifierOptions(), }) => TextClassifierOptions( - baseOptions: BaseOptions(modelAssetBuffer: assetBuffer), + baseOptions: BaseOptions.memory(assetBuffer), classifierOptions: classifierOptions, ); diff --git a/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_result.dart b/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_result.dart index 0e3bfc39..a8c1ff68 100644 --- a/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_result.dart +++ b/packages/mediapipe-task-text/lib/src/tasks/text_classification/containers/text_classifier_result.dart @@ -31,10 +31,10 @@ class TextClassifierResult { /// Factory constructor which converts the C representation of an /// ImageClassifierResult into an actual [ImageClassifierResult]. - factory TextClassifierResult.fromStruct( + factory TextClassifierResult.structToDart( bindings.TextClassifierResult struct) { return TextClassifierResult( - classifications: Classifications.fromStructs( + classifications: Classifications.structsToDart( struct.classifications, struct.classifications_count, ), diff --git a/packages/mediapipe-task-text/lib/src/tasks/text_classification/text_classification_executor.dart b/packages/mediapipe-task-text/lib/src/tasks/text_classification/text_classification_executor.dart index da1a4981..f8bfd76d 100644 --- a/packages/mediapipe-task-text/lib/src/tasks/text_classification/text_classification_executor.dart +++ b/packages/mediapipe-task-text/lib/src/tasks/text_classification/text_classification_executor.dart @@ -102,7 +102,7 @@ class TextClassifierExecutor { /// [TextClassificationResult] object. TextClassifierResult _processResult() { // Convert the results into pure-Dart objects and free all memory - final result = TextClassifierResult.fromStruct(_resultsPtr!.ref); + final result = TextClassifierResult.structToDart(_resultsPtr!.ref); _log.fine('Text classification result: $result'); bindings.text_classifier_close_result(_resultsPtr!); _resultsPtr = null; @@ -143,7 +143,7 @@ class TextClassifierExecutor { _closeErrorMessage = null; } if (isNotNullOrNullPointer(_optionsPtr)) { - calloc.free(_optionsPtr!); + TextClassifierOptions.freeStruct(_optionsPtr!); _optionsPtr = null; } } diff --git a/packages/mediapipe-task-text/pubspec.yaml b/packages/mediapipe-task-text/pubspec.yaml index 830a0af7..25beb57f 100644 --- a/packages/mediapipe-task-text/pubspec.yaml +++ b/packages/mediapipe-task-text/pubspec.yaml @@ -18,10 +18,12 @@ dependencies: logging: ^1.2.0 mediapipe_core: path: ../mediapipe-core + native_assets_cli: ^0.3.0 + native_toolchain_c: ^0.3.0 + path: ^1.8.3 dev_dependencies: ffigen: ^9.0.1 flutter_lints: ^2.0.0 flutter_test: sdk: flutter - path: ^1.8.3 diff --git a/packages/mediapipe-task-text/sdk_downloads.dart b/packages/mediapipe-task-text/sdk_downloads.dart new file mode 100644 index 00000000..41f61c2a --- /dev/null +++ b/packages/mediapipe-task-text/sdk_downloads.dart @@ -0,0 +1,13 @@ +// Generated file. Do not manually edit. +final Map> sdkDownloadUrls = { + 'android': { + 'arm64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/gcp_ubuntu_flutter/release/26/20240118-142736/android_arm64/libtext.so' + }, + 'macos': { + 'arm64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/macos_flutter/release/9/20240118-123515/darwin_arm64/libtext.dylib', + 'x64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/macos_flutter/release/9/20240118-123515/darwin_x86_64/libtext.dylib' + } +}; diff --git a/packages/mediapipe-task-text/test/text_classifier_executor_test.dart b/packages/mediapipe-task-text/test/text_classifier_executor_test.dart index e39e55de..13ad049d 100644 --- a/packages/mediapipe-task-text/test/text_classifier_executor_test.dart +++ b/packages/mediapipe-task-text/test/text_classifier_executor_test.dart @@ -1,3 +1,5 @@ +@Tags(['native-assets']) + import 'dart:io' as io; import 'package:flutter_test/flutter_test.dart'; import 'package:mediapipe_text/mediapipe_text.dart'; @@ -42,9 +44,9 @@ void main() { expect(classifications.headName, equals('probability')); expect(classifications.categories, hasLength(2)); expect(classifications.categories.first.categoryName, equals('positive')); - expect(classifications.categories.first.score, closeTo(0.9919, 0.0001)); + expect(classifications.categories.first.score, closeTo(0.9919, 0.0009)); expect(classifications.categories.last.categoryName, equals('negative')); - expect(classifications.categories.last.score, closeTo(0.00804, 0.00001)); + expect(classifications.categories.last.score, closeTo(0.00804, 0.0009)); executor.close(); }); @@ -61,10 +63,8 @@ void main() { final classifications = result.classifications.first; expect(classifications.headName, equals('probability')); expect(classifications.categories, hasLength(1)); - // expect(classifications.categories.first.categoryName, equals('positive')); - // expect(classifications.categories.first.score, closeTo(0.9919, 0.0001)); expect(classifications.categories.first.categoryName, equals('negative')); - expect(classifications.categories.first.score, closeTo(0.00804, 0.00001)); + expect(classifications.categories.first.score, closeTo(0.00804, 0.0009)); executor.close(); }); @@ -82,7 +82,7 @@ void main() { expect(classifications.headName, equals('probability')); expect(classifications.categories, hasLength(1)); expect(classifications.categories.first.categoryName, equals('positive')); - expect(classifications.categories.first.score, closeTo(0.9919, 0.0001)); + expect(classifications.categories.first.score, closeTo(0.9919, 0.0009)); executor.close(); }); diff --git a/packages/mediapipe-task-text/test/text_classifier_result_test.dart b/packages/mediapipe-task-text/test/text_classifier_result_test.dart new file mode 100644 index 00000000..04028537 --- /dev/null +++ b/packages/mediapipe-task-text/test/text_classifier_result_test.dart @@ -0,0 +1,42 @@ +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mediapipe_core/src/test_utils.dart'; +import 'package:mediapipe_text/mediapipe_text.dart'; +import 'package:mediapipe_core/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart' + as core_bindings; +import 'package:mediapipe_text/src/third_party/mediapipe/generated/mediapipe_text_bindings.dart' + as bindings; + +void main() { + group('TextClassifierResult.structToDart should', () { + test('load an empty object', () { + final Pointer struct = + calloc(); + struct.ref.classifications_count = 0; + struct.ref.has_timestamp_ms = false; + + final result = TextClassifierResult.structToDart(struct.ref); + expect(result.classifications, isEmpty); + expect(result.timestamp, isNull); + }); + + test('load a hydrated object', () { + final Pointer struct = + calloc(); + + final classificationsPtr = calloc(2); + populateClassifications(classificationsPtr[0]); + populateClassifications(classificationsPtr[1]); + + struct.ref.classifications_count = 2; + struct.ref.classifications = classificationsPtr; + struct.ref.has_timestamp_ms = true; + struct.ref.timestamp_ms = 9999999; + + final result = TextClassifierResult.structToDart(struct.ref); + expect(result.classifications, hasLength(2)); + expect(result.timestamp, isNotNull); + }, timeout: const Timeout(Duration(milliseconds: 10))); + }); +} diff --git a/packages/mediapipe-task-text/third_party/mediapipe/tasks/c/text/text_classifier/text_classifier.h b/packages/mediapipe-task-text/third_party/mediapipe/tasks/c/text/text_classifier/text_classifier.h index 8c95768b..fae6c262 100644 --- a/packages/mediapipe-task-text/third_party/mediapipe/tasks/c/text/text_classifier/text_classifier.h +++ b/packages/mediapipe-task-text/third_party/mediapipe/tasks/c/text/text_classifier/text_classifier.h @@ -28,45 +28,44 @@ limitations under the License. extern "C" { #endif - typedef struct ClassificationResult TextClassifierResult; - - // The options for configuring a MediaPipe text classifier task. - struct TextClassifierOptions { - // Base options for configuring MediaPipe Tasks, such as specifying the model - // file with metadata, accelerator options, op resolver, etc. - struct BaseOptions base_options; - - // Options for configuring the classifier behavior, such as score threshold, - // number of results, etc. - struct ClassifierOptions classifier_options; - }; - - // Creates a TextClassifier from the provided `options`. - // Returns a pointer to the text classifier on success. - // If an error occurs, returns `nullptr` and sets the error parameter to an - // an error message (if `error_msg` is not nullptr). You must free the memory - // allocated for the error message. - MP_EXPORT void* text_classifier_create(struct TextClassifierOptions* options, - char** error_msg); - - // Performs classification on the input `text`. Returns `0` on success. - // If an error occurs, returns an error code and sets the error parameter to an - // an error message (if `error_msg` is not nullptr). You must free the memory - // allocated for the error message. - MP_EXPORT int text_classifier_classify(void* classifier, const char* utf8_str, - TextClassifierResult* result, - char** error_msg); - - // Frees the memory allocated inside a TextClassifierResult result. Does not - // free the result pointer itself. - MP_EXPORT void text_classifier_close_result(TextClassifierResult* result); - - // Shuts down the TextClassifier when all the work is done. Frees all memory. - // If an error occurs, returns an error code and sets the error parameter to an - // an error message (if `error_msg` is not nullptr). You must free the memory - // allocated for the error message. - MP_EXPORT int text_classifier_close(void* classifier, - char** error_msg); +typedef struct ClassificationResult TextClassifierResult; + +// The options for configuring a MediaPipe text classifier task. +struct TextClassifierOptions { + // Base options for configuring MediaPipe Tasks, such as specifying the model + // file with metadata, accelerator options, op resolver, etc. + struct BaseOptions base_options; + + // Options for configuring the classifier behavior, such as score threshold, + // number of results, etc. + struct ClassifierOptions classifier_options; +}; + +// Creates a TextClassifier from the provided `options`. +// Returns a pointer to the text classifier on success. +// If an error occurs, returns `nullptr` and sets the error parameter to an +// an error message (if `error_msg` is not `nullptr`). You must free the memory +// allocated for the error message. +MP_EXPORT void* text_classifier_create(struct TextClassifierOptions* options, + char** error_msg); + +// Performs classification on the input `text`. Returns `0` on success. +// If an error occurs, returns an error code and sets the error parameter to an +// an error message (if `error_msg` is not `nullptr`). You must free the memory +// allocated for the error message. +MP_EXPORT int text_classifier_classify(void* classifier, const char* utf8_str, + TextClassifierResult* result, + char** error_msg); + +// Frees the memory allocated inside a TextClassifierResult result. Does not +// free the result pointer itself. +MP_EXPORT void text_classifier_close_result(TextClassifierResult* result); + +// Shuts down the TextClassifier when all the work is done. Frees all memory. +// If an error occurs, returns an error code and sets the error parameter to an +// an error message (if `error_msg` is not `nullptr`). You must free the memory +// allocated for the error message. +MP_EXPORT int text_classifier_close(void* classifier, char** error_msg); #ifdef __cplusplus } // extern C diff --git a/packages/mediapipe-task-vision/sdk_downloads.dart b/packages/mediapipe-task-vision/sdk_downloads.dart new file mode 100644 index 00000000..d01418ed --- /dev/null +++ b/packages/mediapipe-task-vision/sdk_downloads.dart @@ -0,0 +1,13 @@ +// Generated file. Do not manually edit. +final Map> sdkDownloadUrls = { + 'android': { + 'arm64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/gcp_ubuntu_flutter/release/26/20240118-142736/android_arm64/libvision.so' + }, + 'macos': { + 'arm64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/macos_flutter/release/9/20240118-123515/darwin_arm64/libvision.dylib', + 'x64': + 'https://storage.googleapis.com/mediapipe-nightly-public/prod/mediapipe/macos_flutter/release/9/20240118-123515/darwin_x86_64/libvision.dylib' + } +}; diff --git a/tool/builder/bin/main.dart b/tool/builder/bin/main.dart index f00d48a1..ccf00cfb 100644 --- a/tool/builder/bin/main.dart +++ b/tool/builder/bin/main.dart @@ -2,24 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:io' as io; import 'package:args/command_runner.dart'; import 'package:builder/download_model.dart'; +import 'package:builder/sdks_finder.dart'; import 'package:builder/sync_headers.dart'; -import 'package:logging/logging.dart'; final runner = CommandRunner( 'build', 'Performs build operations for google/flutter-mediapipe that ' 'depend on contents in this repository', ) - ..addCommand(SyncHeadersCommand()) - ..addCommand(DownloadModelCommand()); + ..addCommand(DownloadModelCommand()) + ..addCommand(SdksFinderCommand()) + ..addCommand(SyncHeadersCommand()); -void main(List arguments) { - Logger.root.onRecord.listen((LogRecord record) { - io.stdout - .writeln('${record.level.name}: ${record.time}: ${record.message}'); - }); - runner.run(arguments); -} +void main(List arguments) => runner.run(arguments); diff --git a/tool/builder/lib/download_model.dart b/tool/builder/lib/download_model.dart index 14dc889d..a7c9e6d2 100644 --- a/tool/builder/lib/download_model.dart +++ b/tool/builder/lib/download_model.dart @@ -61,6 +61,7 @@ class DownloadModelCommand extends Command with RepoFinderMixin { 'if you use the `custommodel` option, but optional if you use the ' '`model` option.', ); + addVerboseOption(argParser); } static final Map _standardModelSources = { @@ -79,6 +80,7 @@ class DownloadModelCommand extends Command with RepoFinderMixin { @override Future run() async { + setUpLogging(); final io.Directory flutterMediaPipeDirectory = findFlutterMediaPipeRoot(); late final String modelSource; diff --git a/tool/builder/lib/extensions.dart b/tool/builder/lib/extensions.dart new file mode 100644 index 00000000..5f9081a0 --- /dev/null +++ b/tool/builder/lib/extensions.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; +import 'dart:io'; + +extension EasyOutput on Process { + Future> get processedStdErr => _process(this.stderr); + + Future> get processedStdOut => _process(this.stdout); + + Future> _process(Stream> stream) async { + return utf8.decoder + .convert((await stream.toList()) + .fold>([], (arr, el) => arr..addAll(el))) + .split('\n'); + } +} + +/// Returns the last full chunk from a Url-like String. +/// +/// From "/an/awesome/url/", returns "url". +/// From "/an/awesome/url", returns "url". +/// From "/an/awesome/url/", with a depth of 1, returns "awesome" +/// From "/an/awesome/url", with a depth of 1, returns "awesome" +String lastChunk(String url, {int depth = 0}) { + final indexOffset = (url.endsWith('/')) ? -2 - depth : -1 - depth; + final splitUrl = url.split('/'); + return splitUrl[splitUrl.length + indexOffset]; +} + +extension DefaultableMap on Map { + void setDefault(K key, V def) { + if (!containsKey(key)) { + this[key] = def; + } + } +} diff --git a/tool/builder/lib/repo_finder.dart b/tool/builder/lib/repo_finder.dart index f81bd677..4faaa66b 100644 --- a/tool/builder/lib/repo_finder.dart +++ b/tool/builder/lib/repo_finder.dart @@ -5,6 +5,7 @@ import 'dart:io' as io; import 'package:args/args.dart'; import 'package:args/command_runner.dart'; +import 'package:logging/logging.dart'; import 'package:path/path.dart' as path; import 'package:io/ansi.dart'; @@ -34,6 +35,18 @@ mixin RepoFinderMixin on Command { ); } + void addVerboseOption(ArgParser argParser) => + argParser.addFlag('verbose', abbr: 'v', defaultsTo: false); + + void setUpLogging() { + final bool verbose = argResults!['verbose']; + Logger.root.level = verbose ? Level.FINEST : Level.INFO; + Logger.root.onRecord.listen((LogRecord record) { + io.stdout.writeln( + '[${record.loggerName}][${record.level.name}] ${record.message}'); + }); + } + /// Looks upward for the root of the `google/mediapipe` repository. This assumes /// the `dart build` command is executed from within said repository. If it is /// not executed from within, then this searching algorithm will reach the root diff --git a/tool/builder/lib/sdks_finder.dart b/tool/builder/lib/sdks_finder.dart new file mode 100644 index 00000000..c1502705 --- /dev/null +++ b/tool/builder/lib/sdks_finder.dart @@ -0,0 +1,398 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:builder/extensions.dart'; +import 'package:builder/repo_finder.dart'; +import 'package:io/ansi.dart'; +import 'package:logging/logging.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:path/path.dart' as path; + +final _log = Logger('SDKsFinder'); + +/// Structure of flattened build locations suitable for JSON serialization. +/// Format is: +/// { +/// : { +/// : , +/// ... +/// }, +/// ... +/// } +typedef _FlatResults = Map>; + +/// Container for the three flavors of MediaPipe tasks. +enum MediaPipeSdk { + libaudio, + libtext, + libvision; + + String toPackageDir() => switch (this) { + MediaPipeSdk.libaudio => 'mediapipe-task-audio', + MediaPipeSdk.libtext => 'mediapipe-task-text', + MediaPipeSdk.libvision => 'mediapipe-task-vision', + }; +} + +/// Scans the GCS buckets where MediaPipe SDKs are stored, identifies the latest +/// builds for each supported build target, and writes the output to a +/// designated file. +/// +/// [SdksFinderCommand] depends on `gsutil` and a Google-corp account that has +/// permissions to read the necessary buckets, so the idea is to run this +/// command on Googlers' work machines whenever MediaPipe rebuilds SDKs. The +/// manual nature of this command is suboptimal, but there is no precedent for +/// fully automating this portion of the MediaPipe release process, so this +/// command helps by automating a portion of the task. +/// +/// The cache-busting mechanism of Flutter's native assets feature is a hash +/// of the contents of any build dependencies. The output files of this command +/// are included in the build dependencies (as specified by the contents of each +/// package's `build.dart` file), so if this command generates new SDK locations +/// in those files, Flutter's CLI will have a cache miss, will re-run +/// `build.dart` during the build phase, and in turn will download the newest +/// versions of the MediaPipe SDKs onto the developer's machine. +/// +/// Operationally, [SdksFinderCommand]'s implementation involves orchestrating +/// one [_OsFinder] instance for each supported [OS] value, which in turn +/// identifies the correct build that has been uploaded to GCS by MediaPipe +/// release machinery. +/// +/// Usage: +/// ```sh +/// $ cd path/to/flutter-mediapipe +/// $ dart tool/builder/bin/main.dart sdks [-v] +/// ``` +class SdksFinderCommand extends Command with RepoFinderMixin { + SdksFinderCommand() { + addVerboseOption(argParser); + } + @override + String description = + 'Updates MediaPipe SDK manifest files for the current build target'; + + @override + String name = 'sdks'; + + static const _gcsPrefix = 'https://storage.googleapis.com'; + + /// Google Storage bucket which houses all MediaPipe SDK uploads. + static const _bucketName = 'mediapipe-nightly-public/prod/mediapipe'; + + final _finders = <_OsFinder>[ + _OsFinder(OS.android), + _OsFinder(OS.macOS), + // TODO: Add other values as their support is ready + ]; + + @override + Future run() async { + setUpLogging(); + _checkGsUtil(); + final results = _SdkLocations(); + + for (final finder in _finders) { + await for (final sdkLocation in finder.find()) { + results.add(sdkLocation); + } + } + for (final MediaPipeSdk sdk in MediaPipeSdk.values) { + _log.info('Saving locations for ${sdk.name}'); + _writeResults(sdk, results.toMap(sdk)); + } + } + + void _writeResults(MediaPipeSdk sdk, _FlatResults results) { + final file = _getOutputFile(sdk); + _log.fine('Writing data to "${file.absolute.path}"'); + var encoder = JsonEncoder.withIndent(' '); + file.writeAsStringSync('''// Generated file. Do not manually edit. +final Map> sdkDownloadUrls = ${encoder.convert(results).replaceAll('"', "'")}; +'''); + io.Process.start('dart', ['format', file.absolute.path]); + } + + File _getOutputFile(MediaPipeSdk sdk) { + return File( + path.joinAll([ + findFlutterMediaPipeRoot().absolute.path, + 'packages/${sdk.toPackageDir()}', + 'sdk_downloads.dart', + ]), + ); + } + + void _checkGsUtil() async { + if (!io.Platform.isMacOS && !io.Platform.isLinux) { + // `which` is not available on Windows, so allow the command to attempt + // to run on Windows + // TODO: possibly add Windows-specific support + return; + } + final process = await Process.start('which', ['gsutil']); + final exitCode = await process.exitCode; + final List processStdOut = await process.processedStdOut; + if (exitCode != 0) { + stderr.writeln( + wrapWith( + 'Warning: Unexpected exit code $exitCode checking for gsutil. Output:' + '${processStdOut.join('\n')}', + [yellow], + ), + ); + // Not exiting here, since this could be a false-negative. + } + if (processStdOut.isEmpty) { + stderr.writeln( + wrapWith( + 'gsutil command not found. Visit: ' + 'https://cloud.google.com/storage/docs/gsutil_install', + [red], + ), + ); + exit(1); + } + } +} + +/// Main workhorse of the SdksFinderCommand. Navigates folders in GCS to find +/// the location of the latest builds for each [MediaPipeSdk] / [Architecture] +/// combination for the given [OS]. +/// +/// Usage: +/// ```dart +/// final macOsFinder = _OsFinder(OS.macOS); +/// await for (final _SdkLocation sdkLoc in macOsFinder.find()) { +/// doSomethingWithLocation(sdkLoc); +/// } +/// ``` +class _OsFinder { + _OsFinder(this.os); + + /// OS-specific upload directories located immediately inside + /// [SdksFinderCommand._bucketName]. + static const _gcsFolderPaths = { + OS.android: 'gcp_ubuntu_flutter', + OS.iOS: null, + OS.macOS: 'macos_flutter', + }; + + /// File extensions for OS-specific SDKs. + static const _sdkExtensions = { + OS.android: 'so', + OS.iOS: 'dylib', + OS.macOS: 'dylib', + }; + + /// Folders for specific [Target] values, where a Target is an OS/architecture + /// combination. + static const targetFolders = >{ + OS.android: { + 'android_arm64': Architecture.arm64, + }, + OS.iOS: {}, + OS.macOS: { + 'darwin_arm64': Architecture.arm64, + 'darwin_x86_64': Architecture.x64, + }, + }; + + final OS os; + + String get folderPath => '${_gcsFolderPaths[os]!}/release'; + String get extension => _sdkExtensions[os]!; + + /// Scans the appropriate GCS location for all build Ids for the given OS and + /// returns the highest integer found. + Future _getBuildNumber(String path) async { + int highestBuildNumber = 0; + + for (final folder in await _gsUtil(path)) { + late int buildId; + try { + // Grab last chunk, since we're looking for a folder of the + // structure: `.../release/:int/` + buildId = int.parse(lastChunk(folder)); + } catch (e) { + // Probably the `{id}_$folder$` directory + continue; + } + if (buildId > highestBuildNumber) { + highestBuildNumber = buildId; + } + } + _log.fine('Highest build number for $os is $highestBuildNumber'); + return highestBuildNumber; + } + + /// Extracts the date within a build directory, which is where the final + /// artifacts can be found. + /// + /// Usage: + /// ```dart + /// final path = await _getDateOfBuildNumber('.../gcp_ubuntu_flutter/release/', 17); + /// print(path); + /// >>> ".../gcp_ubuntu_flutter/release/17/20231212-090734/" + /// ``` + Future _getDateOfBuildNumber(String path) async { + final foldersInBuild = await _gsUtil(path); + if (foldersInBuild.isEmpty || foldersInBuild.length > 2) { + final paths = + foldersInBuild.map((path) => ' • $path').toList().join('\n'); + _log.warning('Unexpectedly found ${foldersInBuild.length} entries inside ' + 'build folder: $path. Expected 1 or 2, of formats "/[date]/" and ' + 'optionally "/[date]_\$folder\$". Found:\n\n$paths\n'); + } + for (final folderPath in foldersInBuild) { + if (folderPath.endsWith('/')) { + final buildDateFolderPath = lastChunk(folderPath); + _log.fine('$folderPath :: $buildDateFolderPath'); + return buildDateFolderPath; + } + } + throw Exception( + 'Unexpected structure of build folder: "$path". Did not find match.', + ); + } + + /// Receives a [Path] like ".../[os_folder]/release/[build_number]/[date]/" + /// and yields all matching architecture folders within. + Stream _getArchitectectures(String path) async* { + final pathsWithinBuild = []; + final expectedFolders = targetFolders[os]!.keys.toSet(); + for (final pathWithinBuild in await _gsUtil(path)) { + pathsWithinBuild.add(lastChunk(pathWithinBuild)); + final maybeArchitecture = lastChunk(pathWithinBuild); + if (targetFolders[os]!.containsKey(maybeArchitecture)) { + expectedFolders.remove(maybeArchitecture); + yield maybeArchitecture; + } + } + if (expectedFolders.isNotEmpty) { + _log.warning( + 'Did not find all expected folders in "$path".\n ' + 'Expected to find ${targetFolders[os]!.keys.toSet()}.\n ' + 'Did not find $expectedFolders.\n ' + 'Folders in path were: $pathsWithinBuild.', + ); + } + } + + /// Combines the path, file name, and extension into the final, complete path. + /// Additionally, checks whether that file actually exists and returns the + /// String value if it does, or `null` if it does not. + Future _getAndCheckFullPath(String path, MediaPipeSdk sdk) async { + final pathToCheck = '$path/${sdk.name}.${_sdkExtensions[os]!}'; + final output = await _gsUtil(pathToCheck); + if (output.isEmpty) { + return null; + } + return pathToCheck; + } + + Stream<_SdkLocation> find() async* { + _log.info('Finding SDKs for $os'); + String path = folderPath; + final buildNumber = await _getBuildNumber(path); + path = '$path/$buildNumber'; + _log.finest('$os :: build number :: $path'); + final buildDate = await _getDateOfBuildNumber(path); + path = '$path/$buildDate'; + _log.finest('$os :: date :: $path'); + + await for (final String archPath in _getArchitectectures(path)) { + String pathWithArch = '$path/$archPath'; + _log.finest('$os :: $archPath :: $pathWithArch'); + for (final sdk in MediaPipeSdk.values) { + final maybeFinalPath = await _getAndCheckFullPath(pathWithArch, sdk); + _log.finest('$os :: maybeFinalPath :: $maybeFinalPath'); + if (maybeFinalPath != null) { + _log.fine('Found "$maybeFinalPath"'); + yield _SdkLocation( + os: os, + arch: targetFolders[os]![archPath]!, + sdk: sdk, + fullPath: '${SdksFinderCommand._gcsPrefix}/' + '${SdksFinderCommand._bucketName}/$maybeFinalPath', + ); + } + } + } + } +} + +// Runs `gsutil ls` against the path, optionally with the `-r` flag. +Future> _gsUtil(String path, {bool recursive = false}) async { + assert( + !path.startsWith('http'), + 'gsutil requires URIs with the "gs" scheme, which this function will add.', + ); + final cmd = [ + 'ls', + if (recursive) '-r', + 'gs://${SdksFinderCommand._bucketName}/$path', + ]; + _log.finest('Running: `gsutil ${cmd.join(' ')}`'); + final process = await Process.start('gsutil', cmd); + final exitCode = await process.exitCode; + if (exitCode > 1) { + // Exit codes of 1 appear when `gsutil` checks for a file that does not + // exist, which for our purposes does not constitute an actual error, and is + // handled later when `process.processedStdOut` is empty. + stderr.writeln( + wrapWith( + 'Warning: Unexpected exit code $exitCode running ' + '`gsutil ${cmd.join(' ')}`. Output: ' + '${(await process.processedStdOut).join('\n')}', + [red], + ), + ); + exit(exitCode); + } + final processStdout = await process.processedStdOut; + final filtered = (processStdout).where((String line) => line != '').toList(); + return filtered; +} + +/// Simple container for the location of a specific MediaPipe SDK in GCS. +class _SdkLocation { + _SdkLocation({ + required this.os, + required this.arch, + required this.sdk, + required this.fullPath, + }); + final OS os; + final Architecture arch; + final MediaPipeSdk sdk; + final String fullPath; + + @override + String toString() => '_SdkLocation(os: $os, arch: $arch, sdk: $sdk, ' + 'fullPath: $fullPath)'; +} + +/// Container for multiple [_SdkLocation] objects with support for quickly +/// extracting all records for a given MediaPipe task (audio, vision, or text). +class _SdkLocations { + final Map> _locations = {}; + + void add(_SdkLocation loc) { + _locations.setDefault(loc.sdk, <_SdkLocation>[]); + _locations[loc.sdk]!.add(loc); + } + + _FlatResults toMap(MediaPipeSdk sdk) { + if (!_locations.containsKey(sdk)) return {}; + + final _FlatResults results = >{}; + for (_SdkLocation loc in _locations[sdk]!) { + results.setDefault(loc.os.toString(), {}); + results[loc.os.toString()]![loc.arch.toString()] = loc.fullPath; + } + + return results; + } +} diff --git a/tool/builder/lib/sync_headers.dart b/tool/builder/lib/sync_headers.dart index aefe1e97..c4b383e7 100644 --- a/tool/builder/lib/sync_headers.dart +++ b/tool/builder/lib/sync_headers.dart @@ -57,10 +57,12 @@ class SyncHeadersCommand extends Command with RepoFinderMixin { 'at destination locations.', ); addSourceOption(argParser); + addVerboseOption(argParser); } @override Future run() async { + setUpLogging(); final io.Directory flutterMediaPipeDirectory = findFlutterMediaPipeRoot(); final io.Directory mediaPipeDirectory = findMediaPipeRoot( flutterMediaPipeDirectory, diff --git a/tool/builder/pubspec.yaml b/tool/builder/pubspec.yaml index 43d8dce8..33ca0c0c 100644 --- a/tool/builder/pubspec.yaml +++ b/tool/builder/pubspec.yaml @@ -4,7 +4,7 @@ description: Performs build operations for google/flutter-mediapipe that depend version: 1.0.0 # repository: https://github.com/my_org/my_repo environment: - sdk: ^3.2.0-162.0.dev + sdk: ^3.1.5 # Add regular dependencies here. dependencies: @@ -12,6 +12,7 @@ dependencies: http: ^1.1.0 io: ^1.0.4 logging: ^1.2.0 + native_assets_cli: ^0.3.2 path: ^1.8.0 process: ^5.0.0 diff --git a/tool/ci_script_shared.sh b/tool/ci_script_shared.sh index 183f71a5..b911064f 100644 --- a/tool/ci_script_shared.sh +++ b/tool/ci_script_shared.sh @@ -1,3 +1,15 @@ +function ci_text_package() { + # Download bert_classifier.tflite model into example/assets for integration tests + echo "Downloading TextClassification model" + pushd ../../tool/builder + dart pub get + dart bin/main.dart model -m textclassification + popd + + echo `pwd` + ls -lah +} + function ci_package () { local channel="$1" @@ -8,6 +20,10 @@ function ci_package () { echo "== Testing '${PACKAGE_NAME}' on Flutter's $channel channel ==" pushd "packages/${PACKAGE_NAME}" + if [[ $PACKAGE_NAME == "mediapipe-task-text" ]]; then + ci_text_package + fi + # Grab packages. flutter pub get @@ -16,13 +32,36 @@ function ci_package () { # Run the formatter on all the dart files to make sure everything's linted. dart format --output none --set-exit-if-changed . + + # Turn on the native-assets feature required by flutter-mediapipe + flutter config --enable-native-assets - # Run the actual tests. + # Run the actual tests if they exist. if [ -d "test" ] then flutter test fi + # Run any example tests if they exist + if [ -d "example/test" ] + then + echo "Analyzing '${PACKAGE_NAME}/example'" + + pushd "example" + + flutter pub get + + # Run the analyzer to find any static analysis issues. + dart analyze --fatal-infos + + # Run the formatter on all the dart files to make sure everything's linted. + dart format --output none --set-exit-if-changed . + + flutter test + + popd + fi + popd done } diff --git a/tool/mediapipe_ci_script_master.sh b/tool/mediapipe_ci_script_master.sh index 36b461b7..50eff7c1 100755 --- a/tool/mediapipe_ci_script_master.sh +++ b/tool/mediapipe_ci_script_master.sh @@ -8,6 +8,7 @@ source "$DIR/ci_script_shared.sh" flutter doctor -v declare -ar PACKAGE_NAMES=( + # TODO(craiglabenz): Uncomment once native assets works on CI "mediapipe-core" "mediapipe-task-text" )