From bd29aebfbeba4072d78468d3f623017459cc9566 Mon Sep 17 00:00:00 2001 From: datang Date: Mon, 29 Aug 2022 11:42:27 +0800 Subject: [PATCH] all --- .idea/libraries/Dart_Packages.xml | 236 +++++++ .idea/libraries/Dart_SDK.xml | 27 + .idea/libraries/Flutter_Plugins.xml | 7 + .idea/modules.xml | 8 + .idea/permission_handler-10.0.0.iml | 18 + .idea/vcs.xml | 6 + AUTHORS | 8 + CHANGELOG.md | 395 ++++++++++++ LICENSE | 21 + example/README.md | 16 + example/android/app/build.gradle | 55 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 104 ++++ .../com/example/example/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 8 + .../app/src/profile/AndroidManifest.xml | 52 ++ example/android/build.gradle | 27 + example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + example/android/settings.gradle | 15 + example/ios/Flutter/AppFrameworkInfo.plist | 26 + example/ios/Flutter/Debug.xcconfig | 2 + example/ios/Flutter/Release.xcconfig | 2 + example/ios/Podfile | 93 +++ example/ios/Runner.xcodeproj/project.pbxproj | 575 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 ++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ example/ios/Runner/Base.lproj/Main.storyboard | 26 + example/ios/Runner/Info.plist | 103 ++++ example/ios/Runner/Runner-Bridging-Header.h | 1 + example/lib/main.dart | 156 +++++ example/pubspec.yaml | 37 ++ .../res/images/baseflow_logo_def_light-02.png | Bin 0 -> 22696 bytes .../res/images/poweredByBaseflowLogoLight.png | Bin 0 -> 4561 bytes .../images/poweredByBaseflowLogoLight@2x.png | Bin 0 -> 10820 bytes .../images/poweredByBaseflowLogoLight@3x.png | Bin 0 -> 17550 bytes example/windows/CMakeLists.txt | 95 +++ example/windows/flutter/CMakeLists.txt | 103 ++++ .../flutter/generated_plugin_registrant.cc | 17 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 17 + example/windows/runner/CMakeLists.txt | 17 + example/windows/runner/Runner.rc | 121 ++++ example/windows/runner/flutter_window.cpp | 61 ++ example/windows/runner/flutter_window.h | 33 + example/windows/runner/main.cpp | 43 ++ example/windows/runner/resource.h | 16 + example/windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes example/windows/runner/runner.exe.manifest | 20 + example/windows/runner/utils.cpp | 64 ++ example/windows/runner/utils.h | 19 + example/windows/runner/win32_window.cpp | 245 ++++++++ example/windows/runner/win32_window.h | 98 +++ lib/permission_handler.dart | 108 ++++ pubspec.yaml | 36 ++ scripts/before_build_apks.sh | 26 + scripts/before_build_ipas.sh | 10 + test/permission_handler_test.dart | 129 ++++ 94 files changed, 3721 insertions(+) create mode 100644 .idea/libraries/Dart_Packages.xml create mode 100644 .idea/libraries/Dart_SDK.xml create mode 100644 .idea/libraries/Flutter_Plugins.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/permission_handler-10.0.0.iml create mode 100644 .idea/vcs.xml create mode 100644 AUTHORS create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 example/README.md create mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/app/src/main/AndroidManifest.xml create mode 100644 example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/values-night/styles.xml create mode 100644 example/android/app/src/main/res/values/styles.xml create mode 100644 example/android/app/src/profile/AndroidManifest.xml create mode 100644 example/android/build.gradle create mode 100644 example/android/gradle.properties create mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 example/android/settings.gradle create mode 100644 example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 example/ios/Flutter/Debug.xcconfig create mode 100644 example/ios/Flutter/Release.xcconfig create mode 100644 example/ios/Podfile create mode 100644 example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner/AppDelegate.swift create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 example/ios/Runner/Info.plist create mode 100644 example/ios/Runner/Runner-Bridging-Header.h create mode 100644 example/lib/main.dart create mode 100644 example/pubspec.yaml create mode 100644 example/res/images/baseflow_logo_def_light-02.png create mode 100644 example/res/images/poweredByBaseflowLogoLight.png create mode 100644 example/res/images/poweredByBaseflowLogoLight@2x.png create mode 100644 example/res/images/poweredByBaseflowLogoLight@3x.png create mode 100644 example/windows/CMakeLists.txt create mode 100644 example/windows/flutter/CMakeLists.txt create mode 100644 example/windows/flutter/generated_plugin_registrant.cc create mode 100644 example/windows/flutter/generated_plugin_registrant.h create mode 100644 example/windows/flutter/generated_plugins.cmake create mode 100644 example/windows/runner/CMakeLists.txt create mode 100644 example/windows/runner/Runner.rc create mode 100644 example/windows/runner/flutter_window.cpp create mode 100644 example/windows/runner/flutter_window.h create mode 100644 example/windows/runner/main.cpp create mode 100644 example/windows/runner/resource.h create mode 100644 example/windows/runner/resources/app_icon.ico create mode 100644 example/windows/runner/runner.exe.manifest create mode 100644 example/windows/runner/utils.cpp create mode 100644 example/windows/runner/utils.h create mode 100644 example/windows/runner/win32_window.cpp create mode 100644 example/windows/runner/win32_window.h create mode 100644 lib/permission_handler.dart create mode 100644 pubspec.yaml create mode 100755 scripts/before_build_apks.sh create mode 100755 scripts/before_build_ipas.sh create mode 100644 test/permission_handler_test.dart diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml new file mode 100644 index 0000000..460f26e --- /dev/null +++ b/.idea/libraries/Dart_Packages.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml new file mode 100644 index 0000000..3dad229 --- /dev/null +++ b/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml new file mode 100644 index 0000000..b0f6971 --- /dev/null +++ b/.idea/libraries/Flutter_Plugins.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9efb223 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/permission_handler-10.0.0.iml b/.idea/permission_handler-10.0.0.iml new file mode 100644 index 0000000..f568d74 --- /dev/null +++ b/.idea/permission_handler-10.0.0.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..b503219 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ + +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Baseflow +Maurits van Beusekom \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..60d83bb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,395 @@ +## 10.0.0 + +* __BREAKING CHANGE__: Updated Android `compileSdkVersion` to `33` to handle the new `POST_NOTIFICATIONS` permission. +> When updating to version 10.0.0 make sure to update the `android/app/build.gradle` file and set the `compileSdkVersion` to `33`. + +## 9.2.0 + +* Federated permission_handler_windows for the Windows version. + +## 9.1.0 + +* Moved out Android and iOS implementations into their own packages. + +## 9.0.2 + +* Fixes regression when requesting 'locationAlways' permission on Andriod 9 (Pie) and earlier. + +## 9.0.1 + +* Fixes bug when requesting `locationAlways` permissions on Android. +* Solves a compilation error when building the example App on Android. + +## 9.0.0 + +* iOS: Bluetooth permission dialog now appears when requested instead of when the app is initialized. +Note: Requesting Bluetooth status will also prompt the permission dialog (see issue [#591](https://github.com/Baseflow/flutter-permission-handler/issues/591)). + +## 8.3.0 + +* Updated Android Gradle Plugin to 4.1.0 and Gradle Wrapper to 6.7 which is inline with the current Flutter stable version (Flutter 2.5.3). + +## 8.2.6 + +* Fixed broken androidx migration link in the README.md. + +## 8.2.5 + +* Fixed broken link in the README.md. + +## 8.2.4 + +* Solved bug where output would log that there is no permission in manifest for BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE and BLUETOOTH_CONNECT on Android 11 devices and lower(see issue [#691](https://github.com/Baseflow/flutter-permission-handler/issues/691)). + +## 8.2.3 + +* iOS: Enhanced the `bluetooth` permission for iOS 13 and up, so the user gets prompted with the "bluetooth" permission dialog (see issue [#591](https://github.com/Baseflow/flutter-permission-handler/issues/591)). + +## 8.2.2 + +* Updated the README.md to mention setting the `compileSdkVersion` to `31`; +* Added an additional note to version 8.2.0 release notes to inform people to update the `compileSdkVersion`. + +## 8.2.1 + +* Resolved an issue where checking permissions on pre Android M devices always resolved to `PermissionStatus.denied` (see issue [#60](https://github.com/Baseflow/flutter-permission-plugins/issues/60)); +* Updated the url_launcher dependency in the example App to `^6.0.12`. + +## 8.2.0 + +> **IMPORTANT:** when updating to version 8.2.0 make sure to also set the `compileSdkVersion` in the `app/build.gradle` file to `31`. + +* Added support for the new Android 12 Bluetooth permissions: BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE and BLUETOOTH_CONNECT. +* Updated Android compile and target SDK to 31 (Android 12 (S)). +* Updated Gradle and dependencies of Android project. +* Updated applicationID of example app + +## 8.1.6 + +* Android: Fixed a `NullPointerException` when changing permissions in the Location Settings intent. + +## 8.1.5 +* Android: Fixed deprecation warnings/errors when `compileSdkVersion` was set to 31 (Android S/12). + +## 8.1.4+2 + +* iOS: fixed memory error that occurred on iOS 12.2 and below (see issue [#638](https://github.com/Baseflow/flutter-permission-handler/issues/638)). + +## 8.1.4+1 + +* Fix a bug where after allowing the `location` permission and requesting it again would lead to a memory error. + +## 8.1.4 + +* Fix bug where requesting `locationAlways` permission sometimes returns `PermissionStatus.Denied` instead of `PermissionStatus.Granted`. + +## 8.1.3 + +* Fix bug where `locationAlways` returns `PermanentlyDenied`; +* Updated the `README.md` for requesting the `locationAlways` permission the correct way. + +## 8.1.2 + +* Suppress deprecation warnings on iOS for code that specifically targets older iOS versions (see issue [#607](https://github.com/Baseflow/flutter-permission-handler/issues/607)). + +## 8.1.1 + +* Fixed deprecation issue when checking phone capabilities on iOS (see issue [#597](https://github.com/Baseflow/flutter-permission-handler/issues/597)). + +## 8.1.0 + +* Added support for iOS 12+ Critical Alerts permission requesting. + * NOTE: This requires applying to Apple and receiving a special entitlement from them inorder to work. See [this article](https://medium.com/@shashidharyamsani/implementing-ios-critical-alerts-7d82b4bb5026) for an explination on how to use Critical Alerts. +* Added support for Android M+ Access Notification Policy permission requesting (ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS). + * Note: This opens a general page in settings, not specific to the package. + +## 8.0.1 + +* Updated API documentation for the `PermissionStatus.permanentlyDenied` status. + +## 8.0.0+2 + +* Fix broken Podfile link noted at `8.0.0`. +* Fix the information link noted at [Podfile](permission_handler/example/ios/Podfile). + +## 8.0.0+1 + +* Updated the README.md setup section about the Podfile and changed a minor spelling mistake. + +## 8.0.0 + +This release contains the following **breaking changes**: +* Starting from this version the permissions on iOS are disabled by default. To enable a permission, specify the correct `GCC_PREPROCESSOR_DEFINITIONS` in the `ios/Podfile` file. For an example check out the [Podfile](permission_handler/example/ios/Podfile) of the example application. +* Added support for the "AppTrackingTransparency" permission on iOS. + +## 7.2.0 + +* Added support for the "REQUEST_INSTALL_PACKAGES" permission on Android. + +## 7.1.1 + +* Improved the example app by using the Baseflow Plugin Template and move all the functionality to the `main.dart` file. + +## 7.1.0 + +* Added support for the "SYSTEM_ALERT_WINDOW" permission on Android. + +## 7.0.0 + +This release contains the following **breaking changes**: +* Updated compile SDK version to 30 in the build.gradle for handling the MANAGE_EXTERNAL_STORAGE permission; +* Added the MANAGE_EXTERNAL_STORAGE permission for Android R and up; +* Registered listeners on the plugin level to prevent memory leaks or unwanted behaviour. + +## 6.1.3 + +* Implement equality operator on the `Permission` class; +* Updated the README.md with instructions on enabling/ disabling the bluetooth permissions on iOS; +* Corrected some spelling mistakes in the `CHANGELOG.md`. + +## 6.1.2 + +* Correctly handle the ACCESS_MEDIA_LOCATION and ACCESS_ACTIVITY_RECOGNITION permissions on pre Android Q devices (permissions should be implicitly granted on pre Android Q). + +## 6.1.1 + +* Added unit-tests to guard API against breaking changes. + +## 6.1.0 + +* Added support for bluetooth permissions; +* Workaround for ignore battery optimizations on pre-M Android devices (see PR [#376](https://github.com/Baseflow/flutter-permission-handler/pull/376)). + +## 6.0.1+1 + +* Fixed content of the README.md file. + +## 6.0.1 + +* Fixed deprecation warning when building Android project. + +## 6.0.0 + +This release includes the following **breaking changes**: +* Migrated to null safety +* Removed PermissionStatus.undetermined, PermissionStatus.denied will be used instead (see our "[Changes in 6.0.0](https://github.com/Baseflow/flutter-permission-handler/wiki/Changes-in-6.0.0)" wiki page for more details). + +## 5.1.0+2 + +* Solve mismatch with permission constants between Dart and Android (due to addition of permission on iOS); +* Fix compile error which occurred when on iOS the "PERMISSION_PHOTOS" macro is deactivated (meaning code dealing with the `PHPhotoLibrary` library is removed from the code base). + +## 5.1.0+1 + +* Recreate the iOS part of the example project based on the Flutter stable channel (previous version was accidentally created with the Flutter beta channel). + +## 5.1.0 + +* Added support for the limited photos permission available on iOS 14 and up; +* Fixed deprecated warning on iOS; +* Added support for the "READ_PHONE_NUMBERS" permission on Android; +* Fix a link to the contribution guide in the README.md. + +## 5.0.1+2 + +* Pin dependency on permission_handler_platform_interface on version 2.0.1. + +## 5.0.1+1 + +* Fixes Typo +* Issue #233 - on 5.0: Solved a bug that prevented Android applications running in the background to check the permission status. + +## 5.0.1 + +* Update `permission_handler_platform_interface 2.0.1` + +## 5.0.0+hotfix.10 + +* Revert pull-request [#317](https://github.com/Baseflow/flutter-permission-handler/pull/317) + +## 5.0.0+hotfix.9 + +* Solved an issue where kCLAuthorizationStatusAuthorizedWhenInUse was returning PermissionStatusDenied (see [#317](https://github.com/Baseflow/flutter-permission-handler/pull/317)) + +## 5.0.0+hotfix.8 + +* Solved an issue on iOS where requesting notification permissions returned prematurely (see pull-request [#297](https://github.com/Baseflow/flutter-permission-handler/pull/297)) + +## 5.0.0+hotfix.7 + +* ** Mistake release please don't use this version ** + +## 5.0.0+hotfix.6 + +* Solved an issue on iOS where requesting notification permissions always resulted in a "granted" result (see pull-request [#289](https://github.com/Baseflow/flutter-permission-handler/pull/289)) + +## 5.0.0+hotfix.5 + +* Remove use of the deprecated pre iOS 8 API causing users compile issues (see issue [#277](https://github.com/Baseflow/flutter-permission-handler/issues/277)). + +## 5.0.0+hotfix.4 + +* Solve issue on Android causing an IllegalStateException ([#267](https://github.com/Baseflow/flutter-permission-handler/issues/267)). + +## 5.0.0+hotfix.3 + +* Includes the changes of 4.4.0+hotfix.4 (which was released to be backwards compatible). + +## 5.0.0+hotfix.2 + +* Removed some residual usages of the `PermissionStatusUnknown` constants in #ifdef statements that were not found by the compiler. + +## 5.0.0+hotfix.1 + +* Make sure all enums from `permission_handler_platform_interface: 2.0.0` are exposed through the `permission_handler`. + +## 5.0.0 + +* **BREAKING**: Implemented more intuitive API exposed by `permission_handler_platform_interface: 2.0.0` ([#230](https://github.com/Baseflow/flutter-permission-handler/issues/230)). + +## 4.4.0+hotfix.4 + +* Android: solved issue where `permission_handler` is used in a service (see [#251](https://github.com/Baseflow/flutter-permission-handler/issues/251)) + +## 4.4.0+hotfix.3 + +IGNORE THIS VERSION, it was released by accident and contains the same code as 4.4.0+hotfix.2 + +## 4.4.0+hotfix.2 + +* Issue #235: Solved a bug which made it impossible to request service status on Android 7; +* Issue #237: Solved a bug which crashes the application when cancelling the "Ignore battery optimizations" request for permissions. + +## 4.4.0+hotfix.1 + +* Issue #233: Solved a bug that prevented Android applications running in the background to check the permission status. + +## 4.4.0 + +* Updated plugin structure to confirm to the Flutter federated plugin architecture. This will make it easier to add new platform implementations (see: https://medium.com/flutter/how-to-write-a-flutter-web-plugin-part-2-afdddb69ece6); +* Android: Migrate to FlutterPlugin Android API (better support for Add-to-App); +* Android: Suppress JAVA warnings which are generated to old platform code (only executes on older platforms); +* Android: Fixed issue which sometimes resulting in illegal cast exception. + +## 4.3.0 + +* Allow requesting location permissions when location services are disabled (on iOS this will redirect the user to the Location settings page); +* Android: Add support for requesting Activity Recognition permissions; +* Confirm to Effective Dart guidelines; +* Documented all public API members; +* Fixed several typos in the README.md. + +## 4.2.0+hotfix.3 + +* Android: Fixes a bug which in some cases caused the permission `neverAskAgain` to be returned incorrectly. + +## 4.2.0+hotfix.2 + +* Android: Fixes a bug where permissions are reported as `neverAskAgain` incorrectly after calling `requestPermissions` method. + + +## 4.2.0+hotfix.1 + +* Android: Fixes a bug where permissions are reported as `neverAskAgain` incorrectly. + +## 4.2.0 + +* Android: Methods `checkPermissionStatus` and `requestPermissions` now support addition `neverAskAgain` status. + +## 4.1.0 + +* iOS: Added option to exclude permissions logic using macros. This allows developers to submit their app to the AppStore without having to include all permissions in their Info.plist; +* Android: Support ANSWER_PHONE_CALLS permission for API 26 and higher; +* Android: Support ACCESS_MEDIA_LOCATION permission for API 26 and higher; +* Android: Synchronized Gradle version with Flutter stable (1.12.13+hotfix.5). + +## 4.0.0 + +* iOS: Added support for requesting permissions on the DOCUMENTS and DOWNLOADS folder (thanks to @phranck); +* Android: Fix the PROCESS_OUTGOING_CALLS permissions which have been deprecated in API 29. + +## 3.3.0 + +* Android: Add support for requesting the background location permission within the `locationAlways` group. +* Android: Update AGP, Gradle and AndroidX dependencies + +## 3.2.2 + +* Fixed problem with dependency on specific version of gradle wrapper on Android. + +## 3.2.1+1 + +* Reverted the update of the 'meta' plugin since Flutter SDK depends on version 1.1.6 + +## 3.2.1 + +* Updated dependency on 'meta' to latest version. + +## 3.2.0 + +* Add support for Androids' "ignore battery optimizations" permission; +* Improve error logging; +* Documented support for AndroidX. + +## 3.1.0 + +* Support service status inquiry for phone permission on iOS & Android. + +## 3.0.2 + +* Fixed bug when rapidly requesting permissions (#23); +* Rename Enums.h to PermissionHandlerEnums.h to prevent conflicts with geolocator (#104); +* Update the Android permission request code to prevent conflicts with geolocator (#111); +* Update Gradle infrastructure. + +## 3.0.1 + +* Mark the Swift pod as static + +## 3.0.0 + +* Converted the iOS version from Swift to Objective-C, reducing the size of the final binary considerably. + +## 2.2.0 + +* Added new method `checkServiceStatus` to allow users to check if the location services (on Android and iOS) and motion services (iOS only) are enabled; +* When checking permission status (using `checkPermissionStatus`) return `PermissionStatus.disabled` when permissions are granted or denied and the location services (on Android and iOS) or the motion services (iOS only) are disabled. + +## 2.1.3 + +* Fixed bug on iOS where result of the `openAppSettings` call always returned `false`; +* Upgrade Android plugin to support AndroidX and latest Gradle and Kotlin versions; +* Added Swift version number to the Podfile of the plugin; +* Updated flutter static analyzes to conform to latest recommendations. + +## 2.1.2 + +* Make sure the Permission Handler compiles with latest iOS SDK + +## 2.1.1 + +* Update to the latest version of Swift (4.2); +* Make sure that the correct Swift version is set in the `Podfile` of consuming Apps; +* Updated configuration for static code analyses, so it complies with the Flutter recommendations. + +## 2.1.0 + +* Added Android support to check if location services are enabled. If location services are not running the permission check returns `PermissionStatus.DISABLED`. + +## 2.0.1 + +* Fix bug with dependency on `com.android.support:support-compat` library +* Update used Kotlin and Gradle versions + +## 2.0.0 + +* Make methods non static so users can create an instance or override + +## 1.0.1 + +* Converted the plugin into a library so that developers don't have to import additional files; +* Updated the README.md to fix example code. + +## 1.0.0 + +* Initial release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bd6192f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Baseflow + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..f1bcd34 --- /dev/null +++ b/example/README.md @@ -0,0 +1,16 @@ +# permission_handler_example + +Demonstrates how to use the permission_handler plugin. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.io/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..fd8b8db --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,55 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 33 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.baseflow.permissionhandler.example" + minSdkVersion 16 + targetSdkVersion 33 + 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 '../..' +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..d692acb --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..93111d8 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..e793a00 --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..00fa441 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..699d4b0 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..622ddc5 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,27 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc6a58a --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..8d4492f --- /dev/null +++ b/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 + 9.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/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/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/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/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..2c994ff --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,93 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.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__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + + target.build_configurations.each do |config| + # You can remove unused permissions here + # for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h + # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0' + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + + ## dart: PermissionGroup.calendar + 'PERMISSION_EVENTS=1', + + ## dart: PermissionGroup.reminders + 'PERMISSION_REMINDERS=1', + + ## dart: PermissionGroup.contacts + 'PERMISSION_CONTACTS=1', + + ## dart: PermissionGroup.camera + 'PERMISSION_CAMERA=1', + + ## dart: PermissionGroup.microphone + 'PERMISSION_MICROPHONE=1', + + ## dart: PermissionGroup.speech + 'PERMISSION_SPEECH_RECOGNIZER=1', + + ## dart: PermissionGroup.photos + 'PERMISSION_PHOTOS=1', + + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] + 'PERMISSION_LOCATION=1', + + ## dart: PermissionGroup.notification + 'PERMISSION_NOTIFICATIONS=1', + + ## dart: PermissionGroup.mediaLibrary + 'PERMISSION_MEDIA_LIBRARY=1', + + ## dart: PermissionGroup.sensors + 'PERMISSION_SENSORS=1', + + ## dart: PermissionGroup.bluetooth + 'PERMISSION_BLUETOOTH=1', + + ## dart: PermissionGroup.appTrackingTransparency + 'PERMISSION_APP_TRACKING_TRANSPARENCY=1', + + ## dart: PermissionGroup.criticalAlerts + 'PERMISSION_CRITICAL_ALERTS=1', + ] + + end + end +end diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9df3c91 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,575 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 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 */; }; + B501E7F22BA22C455255CE2E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C446183715B92022DDB68882 /* Pods_Runner.framework */; }; +/* End PBXBuildFile 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 = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; 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 = ""; }; + 862A53EA392D32566500E869 /* 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 = ""; }; + 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 = ""; }; + C446183715B92022DDB68882 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CEA40B36DE135D81D16B7399 /* 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 = ""; }; + DA7CB50DE8057A7A8D126AC9 /* 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B501E7F22BA22C455255CE2E /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2982F40ECD3DD26A4434B596 /* Pods */ = { + isa = PBXGroup; + children = ( + CEA40B36DE135D81D16B7399 /* Pods-Runner.debug.xcconfig */, + 862A53EA392D32566500E869 /* Pods-Runner.release.xcconfig */, + DA7CB50DE8057A7A8D126AC9 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 7EF8E4A69F95E4BF7F747BE9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C446183715B92022DDB68882 /* Pods_Runner.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 */, + 2982F40ECD3DD26A4434B596 /* Pods */, + 7EF8E4A69F95E4BF7F747BE9 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + 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 */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 5CF31A8C72B66ABB365E813D /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + D38B08CB85942E5D11545EE3 /* [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 = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 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 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 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 */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 5CF31A8C72B66ABB365E813D /* [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; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + 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"; + }; + D38B08CB85942E5D11545EE3 /* [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; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase 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 = 9.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)"; + DEVELOPMENT_TEAM = 7624MWN53C; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + 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; + }; + 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 = 9.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 = 9.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)"; + DEVELOPMENT_TEAM = 7624MWN53C; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + 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)"; + DEVELOPMENT_TEAM = 7624MWN53C; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + 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 */ + 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/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3db53b6 --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/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/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 0000000..4033f71 --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,103 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + 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 + + UIViewControllerBasedStatusBarAppearance + + + + NSLocationWhenInUseUsageDescription + Need location when in use + NSLocationAlwaysAndWhenInUseUsageDescription + Always and when in use! + NSLocationUsageDescription + Older devices need location. + NSLocationAlwaysUsageDescription + Can I have location always? + + + NSAppleMusicUsageDescription + Music! + kTCCServiceMediaLibrary + media + + + NSCalendarsUsageDescription + Calendars + + + NSCameraUsageDescription + camera + + + NSContactsUsageDescription + contacts + + + NSMicrophoneUsageDescription + microphone + + + NSSpeechRecognitionUsageDescription + speech + + + NSMotionUsageDescription + motion + + + NSPhotoLibraryUsageDescription + photos + + + NSRemindersUsageDescription + reminders + + + NSBluetoothAlwaysUsageDescription + bluetooth + NSBluetoothPeripheralUsageDescription + bluetooth + + + NSUserTrackingUsageDescription + appTrackingTransparency + + diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..96dded2 --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,156 @@ +import 'dart:io'; + +import 'package:baseflow_plugin_template/baseflow_plugin_template.dart'; +import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; + +void main() { + runApp(BaseflowPluginExample( + pluginName: 'Permission Handler', + githubURL: 'https://github.com/Baseflow/flutter-permission-handler', + pubDevURL: 'https://pub.dev/packages/permission_handler', + pages: [PermissionHandlerWidget.createPage()])); +} + +///Defines the main theme color +final MaterialColor themeMaterialColor = + BaseflowPluginExample.createMaterialColor( + const Color.fromRGBO(48, 49, 60, 1)); + +/// A Flutter application demonstrating the functionality of this plugin +class PermissionHandlerWidget extends StatefulWidget { + /// Create a page containing the functionality of this plugin + static ExamplePage createPage() { + return ExamplePage( + Icons.location_on, (context) => PermissionHandlerWidget()); + } + + @override + _PermissionHandlerWidgetState createState() => + _PermissionHandlerWidgetState(); +} + +class _PermissionHandlerWidgetState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: ListView( + children: Permission.values + .where((permission) { + if (Platform.isIOS) { + return permission != Permission.unknown && + permission != Permission.sms && + permission != Permission.storage && + permission != Permission.ignoreBatteryOptimizations && + permission != Permission.accessMediaLocation && + permission != Permission.activityRecognition && + permission != Permission.manageExternalStorage && + permission != Permission.systemAlertWindow && + permission != Permission.requestInstallPackages && + permission != Permission.accessNotificationPolicy && + permission != Permission.bluetoothScan && + permission != Permission.bluetoothAdvertise && + permission != Permission.bluetoothConnect; + } else { + return permission != Permission.unknown && + permission != Permission.mediaLibrary && + permission != Permission.photos && + permission != Permission.photosAddOnly && + permission != Permission.reminders && + permission != Permission.appTrackingTransparency && + permission != Permission.criticalAlerts; + } + }) + .map((permission) => PermissionWidget(permission)) + .toList()), + ); + } +} + +/// Permission widget containing information about the passed [Permission] +class PermissionWidget extends StatefulWidget { + /// Constructs a [PermissionWidget] for the supplied [Permission] + const PermissionWidget(this._permission); + + final Permission _permission; + + @override + _PermissionState createState() => _PermissionState(_permission); +} + +class _PermissionState extends State { + _PermissionState(this._permission); + + final Permission _permission; + PermissionStatus _permissionStatus = PermissionStatus.denied; + + @override + void initState() { + super.initState(); + + _listenForPermissionStatus(); + } + + void _listenForPermissionStatus() async { + final status = await _permission.status; + setState(() => _permissionStatus = status); + } + + Color getPermissionColor() { + switch (_permissionStatus) { + case PermissionStatus.denied: + return Colors.red; + case PermissionStatus.granted: + return Colors.green; + case PermissionStatus.limited: + return Colors.orange; + default: + return Colors.grey; + } + } + + @override + Widget build(BuildContext context) { + return ListTile( + title: Text( + _permission.toString(), + style: Theme.of(context).textTheme.bodyText1, + ), + subtitle: Text( + _permissionStatus.toString(), + style: TextStyle(color: getPermissionColor()), + ), + trailing: (_permission is PermissionWithService) + ? IconButton( + icon: const Icon( + Icons.info, + color: Colors.white, + ), + onPressed: () { + checkServiceStatus( + context, _permission as PermissionWithService); + }) + : null, + onTap: () { + requestPermission(_permission); + }, + ); + } + + void checkServiceStatus( + BuildContext context, PermissionWithService permission) async { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text((await permission.serviceStatus).toString()), + )); + } + + Future requestPermission(Permission permission) async { + final status = await permission.request(); + + setState(() { + print(status); + _permissionStatus = status; + print(_permissionStatus); + }); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..f27debc --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,37 @@ +name: permission_handler_example +description: Demonstrates how to use the permission_handler plugin. + +environment: + sdk: ">=2.15.0 <3.0.0" + +dependencies: + baseflow_plugin_template: + git: + url: https://github.com/Baseflow/baseflow_plugin_template.git + ref: v2.1.0 + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + + permission_handler: + # When depending on this package from a real application you should use: + # permission_handler: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + url_launcher: ^6.0.12 + +flutter: + uses-material-design: true + + assets: + - res/images/baseflow_logo_def_light-02.png + - res/images/poweredByBaseflowLogoLight@3x.png + - packages/baseflow_plugin_template/logo.png + - packages/baseflow_plugin_template/poweredByBaseflow.png + diff --git a/example/res/images/baseflow_logo_def_light-02.png b/example/res/images/baseflow_logo_def_light-02.png new file mode 100644 index 0000000000000000000000000000000000000000..85f071f275a6572658078b2e05b773cf5e006907 GIT binary patch literal 22696 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

9yGp11G?`E!)dXaQu2W~J` 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:_DEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/example/windows/flutter/CMakeLists.txt b/example/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..b2e4bd8 --- /dev/null +++ b/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,103 @@ +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..a0d0bbe --- /dev/null +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,17 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/example/windows/flutter/generated_plugin_registrant.h b/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..ca38d21 --- /dev/null +++ b/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,17 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + permission_handler_windows + url_launcher_windows +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/example/windows/runner/CMakeLists.txt b/example/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..de2d891 --- /dev/null +++ b/example/windows/runner/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) +apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/example/windows/runner/Runner.rc b/example/windows/runner/Runner.rc new file mode 100644 index 0000000..efd0da2 --- /dev/null +++ b/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.baseflow.permissionhandler" "\0" + VALUE "FileDescription", "example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2022 com.baseflow.permissionhandler. All rights reserved." "\0" + VALUE "OriginalFilename", "example.exe" "\0" + VALUE "ProductName", "example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/example/windows/runner/flutter_window.cpp b/example/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..3a11b51 --- /dev/null +++ b/example/windows/runner/flutter_window.cpp @@ -0,0 +1,61 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/example/windows/runner/flutter_window.h b/example/windows/runner/flutter_window.h new file mode 100644 index 0000000..28c2383 --- /dev/null +++ b/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/example/windows/runner/main.cpp b/example/windows/runner/main.cpp new file mode 100644 index 0000000..ead0b22 --- /dev/null +++ b/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/example/windows/runner/resource.h b/example/windows/runner/resource.h new file mode 100644 index 0000000..ddc7f3e --- /dev/null +++ b/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/example/windows/runner/resources/app_icon.ico b/example/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/example/windows/runner/runner.exe.manifest b/example/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..2c680b8 --- /dev/null +++ b/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/example/windows/runner/utils.cpp b/example/windows/runner/utils.cpp new file mode 100644 index 0000000..05b53c0 --- /dev/null +++ b/example/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + if (target_length == 0) { + return std::string(); + } + std::string utf8_string; + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/example/windows/runner/utils.h b/example/windows/runner/utils.h new file mode 100644 index 0000000..3f0e05c --- /dev/null +++ b/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/example/windows/runner/win32_window.cpp b/example/windows/runner/win32_window.cpp new file mode 100644 index 0000000..97f4439 --- /dev/null +++ b/example/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/example/windows/runner/win32_window.h b/example/windows/runner/win32_window.h new file mode 100644 index 0000000..d9bcac1 --- /dev/null +++ b/example/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/lib/permission_handler.dart b/lib/permission_handler.dart new file mode 100644 index 0000000..5e3a7c2 --- /dev/null +++ b/lib/permission_handler.dart @@ -0,0 +1,108 @@ +import 'package:flutter/foundation.dart'; +import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; + +export 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart' + show + Permission, + PermissionStatus, + PermissionStatusGetters, + PermissionWithService, + FuturePermissionStatusGetters, + ServiceStatus, + ServiceStatusGetters, + FutureServiceStatusGetters; + +PermissionHandlerPlatform get _handler => PermissionHandlerPlatform.instance; + +/// Opens the app settings page. +/// +/// Returns [true] if the app settings page could be opened, otherwise [false]. +Future openAppSettings() => _handler.openAppSettings(); + +/// Actions that can be executed on a permission. +extension PermissionActions on Permission { + /// The current status of this permission. + Future get status => _handler.checkPermissionStatus(this); + + /// If you should show a rationale for requesting permission. + /// + /// This is only implemented on Android, calling this on iOS always returns + /// [false]. + Future get shouldShowRequestRationale async { + if (defaultTargetPlatform != TargetPlatform.android) { + return false; + } + + return _handler.shouldShowRequestPermissionRationale(this); + } + + /// Request the user for access to this [Permission], if access hasn't already + /// been grant access before. + /// + /// Returns the new [PermissionStatus]. + Future request() async { + final permissionStatus = (await [this].request())[this]; + return permissionStatus ?? PermissionStatus.denied; + } +} + +/// Shortcuts for checking the [status] of a [Permission]. +extension PermissionCheckShortcuts on Permission { + /// If the user granted this permission. + Future get isGranted => status.isGranted; + + /// If the user denied this permission. + Future get isDenied => status.isDenied; + + /// If the OS denied this permission. The user cannot change the status, + /// possibly due to active restrictions such as parental controls being in + /// place. + /// *Only supported on iOS.* + Future get isRestricted => status.isRestricted; + + /// User has authorized this application for limited photo library access. + /// *Only supported on iOS.(iOS14+)* + Future get isLimited => status.isLimited; + + /// Returns `true` when permissions are denied permanently. + /// + /// When permissions are denied permanently, no new permission dialog will + /// be showed to the user. Consuming Apps should redirect the user to the + /// App settings to change permissions. + Future get isPermanentlyDenied => status.isPermanentlyDenied; +} + +/// Actions that apply only to permissions that have an associated service. +extension ServicePermissionActions on PermissionWithService { + /// Checks the current status of the service associated with this permission. + /// + /// Notes about specific permissions: + /// - **[Permission.phone]** + /// - Android: + /// - The method will return [ServiceStatus.notApplicable] when: + /// - the device lacks the TELEPHONY feature + /// - TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE + /// - when no Intents can be resolved to handle the `tel:` scheme + /// - The method will return [ServiceStatus.disabled] when: + /// - the SIM card is missing + /// - iOS: + /// - The method will return [ServiceStatus.notApplicable] when: + /// - the native code can not find a handler for the `tel:` scheme + /// - The method will return [ServiceStatus.disabled] when: + /// - the mobile network code (MNC) is either 0 or 65535. See + /// https://stackoverflow.com/a/11595365 for details + /// - **PLEASE NOTE that this is still not a perfect indication** of the + /// device's capability to place & connect phone calls as it also depends + /// on the network condition. + Future get serviceStatus => _handler.checkServiceStatus(this); +} + +/// Actions that can be taken on a [List] of [Permission]s. +extension PermissionListActions on List { + /// Requests the user for access to these permissions, if they haven't already + /// been granted before. + /// + /// Returns a [Map] containing the status per requested [Permission]. + Future> request() => + _handler.requestPermissions(this); +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..d425cdd --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,36 @@ +name: permission_handler +description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. +version: 10.0.0 +homepage: https://github.com/baseflow/flutter-permission-handler + +environment: + sdk: ">=2.15.0 <3.0.0" + flutter: ">=2.8.0" + +flutter: + plugin: + platforms: + android: + default_package: permission_handler_android + ios: + default_package: permission_handler_apple + windows: + default_package: permission_handler_windows + +dependencies: + flutter: + sdk: flutter + meta: ^1.7.0 + permission_handler_android: + git: + url: https://git.oa00.com/austin_dai/permission_handler_android.git + permission_handler_apple: ^9.0.2 + permission_handler_windows: ^0.1.0 + permission_handler_platform_interface: ^3.7.0 + +dev_dependencies: + flutter_lints: ^1.0.4 + flutter_test: + sdk: flutter + mockito: ^5.0.1 + plugin_platform_interface: ^2.0.0 diff --git a/scripts/before_build_apks.sh b/scripts/before_build_apks.sh new file mode 100755 index 0000000..e1590ef --- /dev/null +++ b/scripts/before_build_apks.sh @@ -0,0 +1,26 @@ +#!/bin/bash +wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip +mkdir android-sdk +unzip -qq sdk-tools-linux-3859397.zip -d $HOME/android-sdk +export ANDROID_HOME=$HOME/android-sdk +export PATH=$HOME/android-sdk/tools/bin:$PATH +mkdir -p /home/travis/.android # silence sdkmanager warning +echo 'count=0' > /home/travis/.android/repositories.cfg # silence sdkmanager warning + # suppressing output of sdkmanager to keep log under 4MB (travis limit) +echo y | sdkmanager "tools" >/dev/null +echo y | sdkmanager "platform-tools" >/dev/null +echo y | sdkmanager "build-tools;26.0.3" >/dev/null +echo y | sdkmanager "platforms;android-26" >/dev/null +echo y | sdkmanager "extras;android;m2repository" >/dev/null +echo y | sdkmanager "extras;google;m2repository" >/dev/null +echo y | sdkmanager "patcher;v4" >/dev/null +sdkmanager --list +wget http://services.gradle.org/distributions/gradle-4.1-bin.zip +unzip -qq gradle-4.1-bin.zip -d $HOME/gradle-4.1 +export GRADLE_HOME=$HOME/gradle-4.1 +export PATH=$GRADLE_HOME/bin:$PATH +gradle -v +git clone --single-branch --branch stable https://github.com/flutter/flutter.git $HOME/flutter +export PATH=$HOME/flutter/bin:$HOME/flutter/bin/cache/dart-sdk/bin:$PATH +flutter doctor + diff --git a/scripts/before_build_ipas.sh b/scripts/before_build_ipas.sh new file mode 100755 index 0000000..c36c89f --- /dev/null +++ b/scripts/before_build_ipas.sh @@ -0,0 +1,10 @@ +#!/bin/bash +brew update +brew install libimobiledevice +brew install ideviceinstaller +brew install ios-deploy +pod repo update +gem update cocoapods +git clone --single-branch --branch stable https://github.com/flutter/flutter.git $HOME/flutter +export PATH=$HOME/flutter/bin:$HOME/flutter/bin/cache/dart-sdk/bin:$PATH +flutter doctor diff --git a/test/permission_handler_test.dart b/test/permission_handler_test.dart new file mode 100644 index 0000000..2cfabba --- /dev/null +++ b/test/permission_handler_test.dart @@ -0,0 +1,129 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +void main() { + group('PermissionHandler', () { + setUp(() { + PermissionHandlerPlatform.instance = MockPermissionHandlerPlatform(); + }); + + test('openAppSettings', () async { + final hasOpened = await openAppSettings(); + + expect(hasOpened, true); + }); + + test('PermissionActions on Permission: get status', () async { + final permissionStatus = await Permission.calendar.status; + + expect(permissionStatus, PermissionStatus.granted); + }); + + test( + // ignore: lines_longer_than_80_chars + 'PermissionActions on Permission: get shouldShowRequestRationale should return true when on android', + () async { + final mockPermissionHandlerPlatform = PermissionHandlerPlatform.instance; + + when(mockPermissionHandlerPlatform + .shouldShowRequestPermissionRationale(Permission.calendar)) + .thenAnswer((_) => Future.value(true)); + + await Permission.calendar.shouldShowRequestRationale; + + verify(mockPermissionHandlerPlatform + .shouldShowRequestPermissionRationale(Permission.calendar)) + .called(1); + }); + + test('PermissionActions on Permission: request()', () async { + final permissionRequest = Permission.calendar.request(); + + expect(permissionRequest, isA>()); + }); + + test('PermissionCheckShortcuts on Permission: get isGranted', () async { + final isGranted = await Permission.calendar.isGranted; + expect(isGranted, true); + }); + + test('PermissionCheckShortcuts on Permission: get isDenied', () async { + final isDenied = await Permission.calendar.isDenied; + expect(isDenied, false); + }); + + test('PermissionCheckShortcuts on Permission: get isRestricted', () async { + final isRestricted = await Permission.calendar.isRestricted; + expect(isRestricted, false); + }); + + test('PermissionCheckShortcuts on Permission: get isLimited', () async { + final isLimited = await Permission.calendar.isLimited; + expect(isLimited, false); + }); + + test('PermissionCheckShortcuts on Permission: get isPermanentlyDenied', + () async { + final isPermanentlyDenied = await Permission.calendar.isPermanentlyDenied; + expect(isPermanentlyDenied, false); + }); + + test( + // ignore: lines_longer_than_80_chars + 'ServicePermissionActions on PermissionWithService: get ServiceStatus returns the right service status', + () async { + var serviceStatus = await Permission.phone.serviceStatus; + + expect(serviceStatus, ServiceStatus.enabled); + }); + + test( + // ignore: lines_longer_than_80_chars + 'PermissionListActions on List: request() on a list returns a Map', + () async { + var permissionList = []; + final permissionMap = await permissionList.request(); + + expect(permissionMap, isA>()); + }); + }); +} + +class MockPermissionHandlerPlatform extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements + PermissionHandlerPlatform { + @override + Future checkPermissionStatus(Permission permission) => + Future.value(PermissionStatus.granted); + + @override + Future checkServiceStatus(Permission permission) => + Future.value(ServiceStatus.enabled); + + @override + Future openAppSettings() => Future.value(true); + + @override + Future> requestPermissions( + List permissions) { + var permissionsMap = {}; + return Future.value(permissionsMap); + } + + @override + Future shouldShowRequestPermissionRationale(Permission? permission) { + return super.noSuchMethod( + Invocation.method( + #shouldShowPermissionRationale, + [permission], + ), + returnValue: Future.value(true), + ); + } +}