diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml new file mode 100644 index 0000000..8215242 --- /dev/null +++ b/.github/workflows/dart.yml @@ -0,0 +1,19 @@ +name: Flutter Test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: macos-latest + steps: + - uses: actions/checkout@v1 + - uses: subosito/flutter-action@v1 + with: + channel: 'stable' + - run: flutter pub get + - run: flutter test + - run: cd ./example && flutter build ios --simulator -t lib/ios.dart && flutter build apk -t lib/android.dart \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..c283945 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,17 @@ +name: Publish + +on: + push: + tags: + - v*.* +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v1 + with: + channel: 'stable' + - uses: modool/flutter-package-publisher@master + with: + credentialJson: ${{ secrets.CREDENTIAL_JSON }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0de3ec3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,82 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# blutter +blutter_tools + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea + +# Visual Studio Code related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +.flutter-plugins-dependencies + +build/ +coverage/ +artifacts/ +blutter_tools/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java +**/android/**/gen/ + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +pubspec.lock +!**/example/pubspec.lock diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..a6fd6ba --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 20e59316b8b8474554b38493b8ca888794b0234a + channel: unknown + +project_type: package diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d0bd041 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* Initial release. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..203cb47 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +Contributing to the Flutter Object Cache Package +============================================= + +What you will need +------------------ + + * A Linux, Mac OS X, or Windows machine (note: to run and compile iOS specific parts you'll need access to a Mac OS X machine); + * git (used for source version control, installation instruction can be found [here](https://git-scm.com/)); + * The Flutter SDK (installation instructions can be found [here](https://flutter.io/get-started/install/)); + * A personal GitHub account (if you don't have one, you can sign-up for free [here](https://github.com/)) + +Setting up your development environment +--------------------------------------- + + * Fork `https://github.com/modool/flutter_object_cache` into your own GitHub account. If you already have a fork and moving to a new computer, make sure you update you fork. + * If you haven't configured your machine with an SSH key that's known to github, then + follow [GitHub's directions](https://help.github.com/articles/generating-ssh-keys/) + to generate an SSH key. + * Clone your forked repo on your local development machine: `git clone git@github.com:/flutter_object_cache.git` + * Change into the `flutter_object_cache` directory: `cd flutter_object_cache` + * Add an upstream to the original repo, so that fetch from the master repository and not your clone: `git remote add upstream git@github.com:Modool/flutter_object_cache.git` + +Running the example project +--------------------------- + + * Change into the example directory: `cd example` + * Run the App: `flutter run` + +Contribute +---------- + +We really appreciate contributions via GitHub pull requests. To contribute take the following steps: + + * Make sure you are up to date with the latest code on the master: + * `git fetch upstream` + * `git checkout upstream/develop -b ` + * Apply your changes + * Verify your changes and fix potential warnings/ errors: + * Check formatting: `flutter format .` + * Run static analyses: `flutter analyzes` + * Run unit-tests: `flutter test` + * Commit your changes: `git commit -am ""` + * Push changes to your fork: `git push origin ` + +Send us your pull request: + + * Go to `https://github.com/modool/flutter_object_cache` and click the "Compare & pull request" button. + + Please make sure you solved all warnings and errors reported by the static code analyses and that you fill in the full pull request template. Failing to do so will result in us asking you to fix it. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7454bc3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Modool + +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/README.md b/README.md new file mode 100644 index 0000000..602dd81 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Flutter Native Runtime Package + +A native runtime package for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and call native method or variable. + +![Flutter Test](https://github.com/Modool/flutter_native/workflows/Flutter%20Test/badge.svg) [![pub package](https://img.shields.io/pub/v/flutter_native.svg)](https://pub.dartlang.org/packages/flutter_native) [![Build Status](https://app.bitrise.io/app/fa4f5d4bf452bcfb/status.svg?token=HorGpL_AOw2llYz39CjmdQ&branch=master)](https://app.bitrise.io/app/fa4f5d4bf452bcfb) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart) +## Features + +* Access android classes. +* Access ios classes. + +## Usage + +To use this package, add `flutter_native` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). For example: + +```yaml +dependencies: + flutter_object_cache: 0.0.1 +``` + +## API + +### Access native + +```dart +import 'package:flutter_native/flutter_native.dart'; + +// To get system version for ios +final iosDevice = Device(); +final systemVersion = await iosDevice.systemVersion; + +// To get package name for android +final context = Context(); +final packageName = await context.packageName; + +// Instance type for android +final registrarTarget = nativeRuntime.instanceNamed('Registrar'); +``` + +### iOS Support class + +Native Class | Futter Class +-------------|-------------- +-------------|-------------- + UIDevice | Device + UIScreen | Screen + UIApplication | Application + NSBundle | Bundle + NSProcessInfo | Process + NSUserDefaults | UserDefaults + +### Android Support class + +Native Class | Futter Class +---| --- + Context | Context + AssetManager | AssetManager + ClassLoader | ClassLoader + ApplicationInfo | ApplicationInfo + Resources | Resources + ResourcesImpl | ResourcesImpl + SharedPreferences | SharedPreferences + +## Issues + +Please file any issues, bugs or feature request as an issue on our [Github](https://github.com/modool/flutter_native/issues) page. + +## Want to contribute + +If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](CONTRIBUTING.md) and send us your [pull request](https://github.com/modool/flutter_native/pulls). + +## Author + +This Flutter Native package for Flutter is developed by [modool](https://github.com/modool). You can contact us at diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..ac4a906 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,72 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +/build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/example/.metadata b/example/.metadata new file mode 100644 index 0000000..e7e7647 --- /dev/null +++ b/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 20e59316b8b8474554b38493b8ca888794b0234a + channel: unknown + +project_type: app diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..e43501d --- /dev/null +++ b/example/README.md @@ -0,0 +1,16 @@ +# flutter_native_example + +Demonstrates how to use the flutter_native package. + +## 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.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..0a741cb --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..69b9df4 --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,63 @@ +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 plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.flutter_native_example" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..df498d9 --- /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..7036d05 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/example/flutter_native_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/flutter_native_example/MainActivity.kt new file mode 100644 index 0000000..f25cab5 --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/flutter_native_example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.flutter_native_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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 0000000..db77bb4 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ 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 0000000..17987b7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ 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 0000000..d5f1c8d Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ 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 0000000..4d6372e Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ 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..1f83a33 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..df498d9 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..3100ad2 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + 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..296b146 --- /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-5.6.2-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id new file mode 100644 index 0000000..44a6663 --- /dev/null +++ b/example/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +51a30562b4b6fc46fac1c6e9a43b48b6 \ No newline at end of file diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..6b4c0f7 --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..e8efba1 --- /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/Flutter.podspec b/example/ios/Flutter/Flutter.podspec new file mode 100644 index 0000000..5ca3041 --- /dev/null +++ b/example/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# NOTE: This podspec is NOT to be published. It is only used as a local source! +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'High-performance, high-fidelity mobile apps.' + s.description = <<-DESC +Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. + DESC + s.homepage = 'https://flutter.io' + s.license = { :type => 'MIT' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '8.0' + s.vendored_frameworks = 'Flutter.framework' +end diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..399e934 --- /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/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..17a55d6 --- /dev/null +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Volumes/Mac_Data/opt/flutter" +export "FLUTTER_APPLICATION_PATH=/Volumes/Mac_Data/repositories/flutter_native/example" +export "FLUTTER_TARGET=/Volumes/Mac_Data/repositories/flutter_native/example/lib/ios.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "OTHER_LDFLAGS=$(inherited) -framework Flutter" +export "FLUTTER_FRAMEWORK_DIR=/Volumes/Mac_Data/opt/flutter/bin/cache/artifacts/engine/ios" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.packages" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..f7d6a5e --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,38 @@ +# 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 + 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) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..1227d34 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - Flutter (1.0.0) + - flutter_native_runtime (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - flutter_native_runtime (from `.symlinks/plugins/flutter_native_runtime/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + flutter_native_runtime: + :path: ".symlinks/plugins/flutter_native_runtime/ios" + +SPEC CHECKSUMS: + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + flutter_native_runtime: f26548a323429aa0360527ab31e7a75a0ed28ccb + +PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d + +COCOAPODS: 1.10.0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9353506 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,564 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0B609D40952E8DCDE509A71E /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C6E633B0F03328F6EEAA17F /* libPods-Runner.a */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 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 */; }; +/* 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 */ + 08756E8AACA467A34D78F635 /* 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 = ""; }; + 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 = ""; }; + 5A16E2E9CC6D3FBC1E9B259A /* 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 = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 8C6E633B0F03328F6EEAA17F /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 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; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 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 = ""; }; + EA5946D621FADF6C21465DAF /* 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B609D40952E8DCDE509A71E /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8CA802AD3013C3ACAAB760FB /* Pods */ = { + isa = PBXGroup; + children = ( + 08756E8AACA467A34D78F635 /* Pods-Runner.debug.xcconfig */, + EA5946D621FADF6C21465DAF /* Pods-Runner.release.xcconfig */, + 5A16E2E9CC6D3FBC1E9B259A /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + 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 */, + 8CA802AD3013C3ACAAB760FB /* Pods */, + F1AE03E3DAB442F7708F4C0C /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + F1AE03E3DAB442F7708F4C0C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8C6E633B0F03328F6EEAA17F /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + A7473F409536131B71DE67DA /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 622D12B9EA996BB0ABCAB83B /* [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 = 1020; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + 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 */, + 9740EEB41CF90195004384FC /* Debug.xcconfig 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"; + }; + 622D12B9EA996BB0ABCAB83B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + 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"; + }; + A7473F409536131B71DE67DA /* [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; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = 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; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + 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.flutterNativeRuntimeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + 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 = 8.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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + 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.flutterNativeRuntimeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + 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.flutterNativeRuntimeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + 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..1d526a1 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + 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..002012a --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/AppDelegate.h b/example/ios/Runner/AppDelegate.h new file mode 100644 index 0000000..36e21bb --- /dev/null +++ b/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m new file mode 100644 index 0000000..59a72e9 --- /dev/null +++ b/example/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end 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 0000000..3d43d11 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ 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 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ 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 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ 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 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ 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 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ 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 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ 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 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ 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 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ 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 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ 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 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ 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..b24a7b0 --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_native_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 + + + diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m new file mode 100644 index 0000000..dff6597 --- /dev/null +++ b/example/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/example/lib/android.dart b/example/lib/android.dart new file mode 100644 index 0000000..85edce8 --- /dev/null +++ b/example/lib/android.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +final nativeRuntime = NativeRuntime(); + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + final androidBuild = Build.system(); + final androidContext = + Context(nativeRuntime.instanceNamed('Registrar').method('context')); + final androidContext2 = Context( + nativeRuntime.instanceNamed('Registrar').memberVariable('mAppContext')); + + String model; + String packageName; + String packageName2; + + @override + void initState() { + androidBuild.model.then((model) { + setState(() { + this.model = model; + }); + }); + + androidContext.packageName.then((packageName) { + setState(() { + this.packageName = packageName; + }); + }); + androidContext2.packageName.then((packageName) { + setState(() { + packageName2 = packageName; + }); + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: Column( + children: [ + Text('Class(android.os.Build)->MODEL: $model'), + Text('Registrar.context().getPackageName(): $packageName'), + Text('Registrar->mAppContext.getPackageName(): $packageName2'), + ], + ), + ), + ); + } +} diff --git a/example/lib/ios.dart b/example/lib/ios.dart new file mode 100644 index 0000000..516566a --- /dev/null +++ b/example/lib/ios.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +final nativeRuntime = NativeRuntime(); + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + String systemVersion; + String processName; + Map map; + + bool idleDisabled = false; + + final userDefaults = UserDefaults.named( + 'test_name', nativeRuntime.classNamed('NSUserDefaults')); + final device = Device.current(); + final process = Process.system(); + final bundle = Bundle.main(); + final application = Application.application(); + + String customUserDefaultValue; + + @override + void initState() { + userDefaults.then((defaults) async { + await defaults.setObject('1', 'test_key'); + customUserDefaultValue = await defaults.objectForKey('test_key'); + + map = await defaults.representation; + setState(() {}); + }); + + device.systemVersion.then((version) { + systemVersion = version; + setState(() {}); + }); + + process.name.then((name) { + processName = name; + setState(() {}); + }); + application.idleTimerDisabled.then((disabled) { + idleDisabled = disabled; + }); + + Future.delayed(const Duration(seconds: 10), () async { + await application.setIdleTimerDisabled(disabled: true); + idleDisabled = await application.idleTimerDisabled; + setState(() {}); + }); + super.initState(); + } + + @override + Future dispose() async { + await (await userDefaults).dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: Column( + children: [ + Text('UIDevice.currentDevice.systemVersion: $systemVersion'), + Text('NSProcessInfo: processName: ${processName.toString()}'), + Text( + 'NSUserDefaults: dictionaryRepresentation: ${processName.toString()}'), + Text( + '[[NSUserDefaults alloc] initWithSuiteName: @"test_name"] : test_key : $customUserDefaultValue'), + Text('application.idleTimerDisabled : $idleDisabled'), + ], + ), + ), + ); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..c7885bd --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,189 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.5.0-nullsafety.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0-nullsafety.1" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0-nullsafety.3" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0-nullsafety.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0-nullsafety.1" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.15.0-nullsafety.3" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0-nullsafety.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_native: + dependency: "direct dev" + description: + path: ".." + relative: true + source: path + version: "0.0.1" + flutter_native_runtime: + dependency: transitive + description: + name: flutter_native_runtime + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.10-nullsafety.1" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0-nullsafety.3" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.0-nullsafety.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.0-nullsafety.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0-nullsafety.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0-nullsafety.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0-nullsafety.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0-nullsafety.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.19-nullsafety.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0-nullsafety.3" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.4" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0-nullsafety.3" +sdks: + dart: ">=2.10.0-110 <2.11.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..02ad0d9 --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,64 @@ +name: flutter_native_example +description: Demonstrates how to use the flutter_native_runtime plugin. +publish_to: 'none' +version: 0.0.1+1 + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_native: + path: ../ + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/lib/flutter_native.dart b/lib/flutter_native.dart new file mode 100644 index 0000000..6f86a32 --- /dev/null +++ b/lib/flutter_native.dart @@ -0,0 +1,17 @@ +library flutter_native; + +export 'src/android/application_info.dart'; +export 'src/android/asset_manager.dart'; +export 'src/android/build.dart'; +export 'src/android/class_loader.dart'; +export 'src/android/context.dart'; +export 'src/android/resources.dart'; +export 'src/android/resources_impl.dart'; +export 'src/android/shared_preference.dart'; + +export 'src/ios/application.dart'; +export 'src/ios/bundle.dart'; +export 'src/ios/device.dart'; +export 'src/ios/process.dart'; +export 'src/ios/screen.dart'; +export 'src/ios/user_defaults.dart'; diff --git a/lib/src/android/application_info.dart b/lib/src/android/application_info.dart new file mode 100644 index 0000000..660f320 --- /dev/null +++ b/lib/src/android/application_info.dart @@ -0,0 +1,572 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class ApplicationInfo { + ApplicationInfo(this._target, this._classTarget); + + factory ApplicationInfo.from(NativeTarget target) => + ApplicationInfo(target, classTarget); + + static final classTarget = + NativeRuntime().classNamed('android.content.pm.ApplicationInfo'); + + final NativeTarget _classTarget; + + final NativeTarget _target; + + /// Default task affinity of all activities in this application. See + /// {@link ActivityInfo#taskAffinity} for more information. This comes + /// from the "taskAffinity" attribute. + /// + Future get taskAffinity => + _target.memberVariable('taskAffinity').get(); + + /// Optional name of a permission required to be able to access this + /// application's components. From the "permission" attribute. + /// + Future get permission => + _target.memberVariable('permission').get(); + + /// The name of the process this application should run in. From the + /// "process" attribute or, if not set, the same as + /// packageName. + /// + Future get processName => + _target.memberVariable('processName').get(); + + /// Class implementing the Application object. From the "class" + /// attribute. + /// + Future get className => + _target.memberVariable('className').get(); + + /// A style resource identifier (in the package's resources) of the + /// description of an application. From the "description" attribute + /// or, if not set, 0. + /// + Future get descriptionRes => + _target.memberVariable('descriptionRes').get(); + + /// A style resource identifier (in the package's resources) of the + /// default visual theme of the application. From the "theme" attribute + /// or, if not set, 0. + /// + Future get theme => _target.memberVariable('theme').get(); + + /// Class implementing the Application's manage space + /// functionality. From the "manageSpaceActivity" + /// attribute. This is an optional attribute and will be null if + /// applications don't specify it in their manifest + /// + Future get manageSpaceActivityName => + _target.memberVariable('manageSpaceActivityName').get(); + + /// Class implementing the Application's backup functionality. From + /// the "backupAgent" attribute. This is an optional attribute and + /// will be null if the application does not specify it in its manifest. + /// + ///

If android:allowBackup is set to false, this attribute is ignored. + /// + Future get backupAgentName => + _target.memberVariable('backupAgentName').get(); + + /// An optional attribute that indicates the app supports automatic backup of app data. + ///

0 is the default and means the app's entire data folder + managed external storage will + /// be backed up; + /// Any negative value indicates the app does not support full-data backup, though it may still + /// want to participate via the traditional key/value backup API; + /// A positive number specifies an xml resource in which the application has defined its backup + /// include/exclude criteria. + ///

If android:allowBackup is set to false, this attribute is ignored. + /// + /// @see android.content.Context#getNoBackupFilesDir() + /// @see #FLAG_ALLOW_BACKUP + /// + /// @hide + /// + Future get fullBackupContent => + _target.memberVariable('fullBackupContent').get(); + + /// The default extra UI options for activities in this application. + /// Set from the {@link android.R.attr#uiOptions} attribute in the + /// activity's manifest. + /// + Future get uiOptions => _target.memberVariable('uiOptions').get(); + + /// Private/hidden flags. See {@code PRIVATE_FLAG_...} constants. + /// @hide + /// + Future get privateFlags => + _target.memberVariable('privateFlags').get(); + + /// The required smallest screen width the application can run on. If 0, + /// nothing has been specified. Comes from + /// {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp + /// android:requiresSmallestWidthDp} attribute of the <supports-screens> tag. + /// + Future get requiresSmallestWidthDp => + _target.memberVariable('requiresSmallestWidthDp').get(); + + /// The maximum smallest screen width the application is designed for. If 0, + /// nothing has been specified. Comes from + /// {@link android.R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp + /// android:compatibleWidthLimitDp} attribute of the <supports-screens> tag. + /// + Future get compatibleWidthLimitDp => + _target.memberVariable('compatibleWidthLimitDp').get(); + + /// The maximum smallest screen width the application will work on. If 0, + /// nothing has been specified. Comes from + /// {@link android.R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp + /// android:largestWidthLimitDp} attribute of the <supports-screens> tag. + /// + Future get largestWidthLimitDp => + _target.memberVariable('largestWidthLimitDp').get(); + + /// Value indicating the maximum aspect ratio the application supports. + ///

+ /// 0 means unset. + /// @See {@link android.R.attr#maxAspectRatio}. + /// @hide + /// + Future get maxAspectRatio => + _target.memberVariable('maxAspectRatio').get(); + + Future get volumeUuid => + _target.memberVariable('volumeUuid').get(); + + Future get scanSourceDir => + _target.memberVariable('scanSourceDir').get(); + + Future get scanPublicSourceDir => + _target.memberVariable('scanPublicSourceDir').get(); + + /// Full path to the base APK for this application. + /// + Future get sourceDir => + _target.memberVariable('sourceDir').get(); + + /// Full path to the publicly available parts of {@link #sourceDir}, + /// including resources and manifest. This may be different from + /// {@link #sourceDir} if an application is forward locked. + /// + Future get publicSourceDir => + _target.memberVariable('publicSourceDir').get(); + + /// The names of all installed split APKs, ordered lexicographically. + /// + Future> get splitNames => + _target.memberVariable('splitNames').get>(); + + /// Full paths to zero or more split APKs, indexed by the same order as {@link #splitNames}. + /// + Future> get splitSourceDirs => + _target.memberVariable('splitSourceDirs').get>(); + + /// Full path to the publicly available parts of {@link #splitSourceDirs}, + /// including resources and manifest. This may be different from + /// {@link #splitSourceDirs} if an application is forward locked. + /// + /// @see #splitSourceDirs + /// + Future> get splitPublicSourceDirs => + _target.memberVariable('splitPublicSourceDirs').get>(); + + /// Full paths to the locations of extra resource packages (runtime overlays) + /// this application uses. This field is only used if there are extra resource + /// packages, otherwise it is null. + /// + /// {@hide} + /// + Future> get resourceDirs => + _target.memberVariable('resourceDirs').get>(); + + /// String retrieved from the seinfo tag found in selinux policy. This value can be set through + /// the mac_permissions.xml policy construct. This value is used for setting an SELinux security + /// context on the process as well as its data directory. + /// + /// {@hide} + /// + Future get seInfo => _target.memberVariable('seInfo').get(); + + /// The seinfo tag generated per-user. This value may change based upon the + /// user's configuration. For example, when an instant app is installed for + /// a user. It is an error if this field is ever {@code null} when trying to + /// start a new process. + ///

NOTE: We need to separate this out because we modify per-user values + /// multiple times. This needs to be refactored since we're performing more + /// work than necessary and these values should only be set once. When that + /// happens, we can merge the per-user value with the seInfo state above. + /// + /// {@hide} + /// + Future get seInfoUser => + _target.memberVariable('seInfoUser').get(); + + /// Paths to all shared libraries this application is linked against. This + /// field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES + /// PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving + /// the structure. + /// + Future> get sharedLibraryFiles => + _target.memberVariable('sharedLibraryFiles').get>(); + + /// Full path to the default directory assigned to the package for its + /// persistent data. + /// + Future get dataDir => _target.memberVariable('dataDir').get(); + + /// Full path to the device-protected directory assigned to the package for + /// its persistent data. + /// + /// @see Context#createDeviceProtectedStorageContext() + /// + Future get deviceProtectedDataDir => + _target.memberVariable('deviceProtectedDataDir').get(); + + /// Full path to the credential-protected directory assigned to the package + /// for its persistent data. + /// + /// @hide + /// + Future get credentialProtectedDataDir => + _target.memberVariable('credentialProtectedDataDir').get(); + + /// Full path to the directory where native JNI libraries are stored. + /// + Future get nativeLibraryDir => + _target.memberVariable('nativeLibraryDir').get(); + + /// Full path where unpacked native libraries for {@link #secondaryCpuAbi} + /// are stored, if present. + /// + /// The main reason this exists is for bundled multi-arch apps, where + /// it's not trivial to calculate the location of libs for the secondary abi + /// given the location of the primary. + /// + /// @hide + /// + Future get secondaryNativeLibraryDir => + _target.memberVariable('secondaryNativeLibraryDir').get(); + + /// The root path where unpacked native libraries are stored. + ///

+ /// When {@link #nativeLibraryRootRequiresIsa} is set, the libraries are + /// placed in ISA-specific subdirectories under this path, otherwise the + /// libraries are placed directly at this path. + /// + /// @hide + /// + Future get nativeLibraryRootDir => + _target.memberVariable('nativeLibraryRootDir').get(); + + /// Flag indicating that ISA must be appended to + /// {@link #nativeLibraryRootDir} to be useful. + /// + /// @hide + /// + Future get nativeLibraryRootRequiresIsa => + _target.memberVariable('nativeLibraryRootRequiresIsa').get(); + + /// The primary ABI that this application requires, This is inferred from the ABIs + /// of the native JNI libraries the application bundles. Will be {@code null} + /// if this application does not require any particular ABI. + /// + /// If non-null, the application will always be launched with this ABI. + /// + /// {@hide} + /// + Future get primaryCpuAbi => + _target.memberVariable('primaryCpuAbi').get(); + + /// The secondary ABI for this application. Might be non-null for multi-arch + /// installs. The application itself never uses this ABI, but other applications that + /// use its code might. + /// + /// {@hide} + /// + Future get secondaryCpuAbi => + _target.memberVariable('secondaryCpuAbi').get(); + + /// The kernel user-ID that has been assigned to this application; + /// currently this is not a unique ID (multiple applications can have + /// the same uid). + /// + Future get uid => _target.memberVariable('uid').get(); + + /// The minimum SDK version this application can run on. It will not run + /// on earlier versions. + /// + Future get minSdkVersion => + _target.memberVariable('minSdkVersion').get(); + + /// The minimum SDK version this application targets. It may run on earlier + /// versions, but it knows how to work with any new behavior added at this + /// version. Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT} + /// if this is a development build and the app is targeting that. You should + /// compare that this number is >= the SDK version number at which your + /// behavior was introduced. + /// + Future get targetSdkVersion => + _target.memberVariable('targetSdkVersion').get(); + + /// The app's declared version code. + /// @hide + /// + Future get longVersionCode => + _target.memberVariable('longVersionCode').get(); + + /// An integer representation of the app's declared version code. This is being left in place as + /// some apps were using reflection to access it before the move to long in + /// {@link android.os.Build.VERSION_CODES#P} + /// @deprecated Use {@link #longVersionCode} instead. + /// @hide + /// + Future get versionCode => + _target.memberVariable('versionCode').get(); + + /// The user-visible SDK version (ex. 26) of the framework against which the application claims + /// to have been compiled, or {@code 0} if not specified. + ///

+ /// This property is the compile-time equivalent of + /// {@link android.os.Build.VERSION#CODENAME Build.VERSION.SDK_INT}. + /// + /// @hide For platform use only; we don't expect developers to need to read this value. + /// + Future get compileSdkVersion => + _target.memberVariable('compileSdkVersion').get(); + + /// The development codename (ex. "O", "REL") of the framework against which the application + /// claims to have been compiled, or {@code null} if not specified. + ///

+ /// This property is the compile-time equivalent of + /// {@link android.os.Build.VERSION#CODENAME Build.VERSION.CODENAME}. + /// + /// @hide For platform use only; we don't expect developers to need to read this value. + /// + Future get compileSdkVersionCodename => + _target.memberVariable('compileSdkVersionCodename').get(); + + /// When false, indicates that all components within this application are + /// considered disabled, regardless of their individually set enabled status. + /// + Future get enabled => _target.memberVariable('enabled').get(); + + /// For convenient access to the current enabled setting of this app. + /// @hide + /// + Future get enabledSetting => + _target.memberVariable('enabledSetting').get(); + + /// For convenient access to package's install location. + /// @hide + /// + Future get installLocation => + _target.memberVariable('installLocation').get(); + + /// Resource file providing the application's Network Security Config. + /// @hide + /// + Future get networkSecurityConfigRes => + _target.memberVariable('networkSecurityConfigRes').get(); + + /// Version of the sandbox the application wants to run in. + /// @hide + /// + Future get targetSandboxVersion => + _target.memberVariable('targetSandboxVersion').get(); + + /// The factory of this package, as specified by the <manifest> + /// tag's {@link android.R.styleable#AndroidManifestApplication_appComponentFactory} + /// attribute. + /// + Future get appComponentFactory => + _target.memberVariable('appComponentFactory').get(); + + /// The category of this app. Categories are used to cluster multiple apps + /// together into meaningful groups, such as when summarizing battery, + /// network, or disk usage. Apps should only define this value when they fit + /// well into one of the specific categories. + ///

+ /// Set from the {@link android.R.attr#appCategory} attribute in the + /// manifest. If the manifest doesn't define a category, this value may have + /// been provided by the installer via + /// {@link PackageManager#setApplicationCategoryHint(String, int)}. + /// + Future get category => _target.memberVariable('category').get(); + + Future get classLoaderName => + _target.memberVariable('classLoaderName').get(); + + Future> get splitClassLoaderNames => + _target.memberVariable('splitClassLoaderNames').get>(); + + Future isValidHiddenApiEnforcementPolicy(int policy) => + _classTarget.method('isValidHiddenApiEnforcementPolicy', + arguments: [policy]).invoke(); + + Future get mHiddenApiPolicy => + _target.memberVariable('mHiddenApiPolicy').get(); + + /// @return true if "supportsRtl" has been set to true in the AndroidManifest + /// @hide + /// + Future get hasRtlSupport => + _target.method('hasRtlSupport').invoke(); + + Future get hasCode => _target.method('hasCode').invoke(); + + /// Disable compatibility mode + /// + /// @hide + /// + Future disableCompatibilityMode() => + _target.method('disableCompatibilityMode').invoke(); + + /// Is using compatibility mode for non densty aware legacy applications. + /// + /// @hide + /// + Future get usesCompatibilityMode => + _target.method('usesCompatibilityMode').invoke(); + + Future initForUser(int userId) => + _target.method('initForUser', arguments: [userId]).invoke(); + + Future get packageWhitelistedForHiddenApis => + _target.method('isPackageWhitelistedForHiddenApis').invoke(); + + Future get allowedToUseHiddenApis => + _target.method('isAllowedToUseHiddenApis').invoke(); + + Future get hiddenApiEnforcementPolicy => + _target.method('getHiddenApiEnforcementPolicy').invoke(); + + /// @hide + /// + Future setHiddenApiEnforcementPolicy(int policy) => + _target.method('setHiddenApiEnforcementPolicy', + arguments: [policy]).invoke(); + + /// Updates the hidden API enforcement policy for this app from the given values, if appropriate. + /// + /// This will have no effect if this app is not subject to hidden API enforcement, i.e. if it + /// is on the package whitelist. + /// + /// @param policyPreP configured policy for pre-P apps, or {@link + /// #HIDDEN_API_ENFORCEMENT_DEFAULT} if nothing configured. + /// @param policyP configured policy for apps targeting P or later, or {@link + /// #HIDDEN_API_ENFORCEMENT_DEFAULT} if nothing configured. + /// @hide + /// + Future maybeUpdateHiddenApiEnforcementPolicy() => + _target.method('maybeUpdateHiddenApiEnforcementPolicy').invoke(); + + /// @hide + /// + Future setVersionCode(int newVersionCode) => _target + .method('setVersionCode', arguments: [newVersionCode]).invoke(); + + Future get isDefaultToDeviceProtectedStorage => + _target.method('isDefaultToDeviceProtectedStorage').invoke(); + + Future get isDirectBootAware => + _target.method('isDirectBootAware').invoke(); + + Future get isEncryptionAware => + _target.method('isEncryptionAware').invoke(); + + Future get isExternal => _target.method('isExternal').invoke(); + + Future get isExternalAsec => + _target.method('isExternalAsec').invoke(); + + Future get isForwardLocked => + _target.method('isForwardLocked').invoke(); + + /// True if the application is installed as an instant app. + /// @hide + /// + Future get isInstantApp => + _target.method('isInstantApp').invoke(); + + Future get isInternal => _target.method('isInternal').invoke(); + + Future get isOem => _target.method('isOem').invoke(); + + Future get isPartiallyDirectBootAware => + _target.method('isPartiallyDirectBootAware').invoke(); + + Future get isSignedWithPlatformKey => + _target.method('isSignedWithPlatformKey').invoke(); + + Future get isPrivilegedApp => + _target.method('isPrivilegedApp').invoke(); + + Future get isRequiredForSystemUser => + _target.method('isRequiredForSystemUser').invoke(); + + Future get isStaticSharedLibrary => + _target.method('isStaticSharedLibrary').invoke(); + + Future get isSystemApp => _target.method('isSystemApp').invoke(); + + Future get isUpdatedSystemApp => + _target.method('isUpdatedSystemApp').invoke(); + + Future get isVendor => _target.method('isVendor').invoke(); + + Future get isProduct => _target.method('isProduct').invoke(); + + /// Returns whether or not this application was installed as a virtual preload. + /// + Future get isVirtualPreload => + _target.method('isVirtualPreload').invoke(); + + /// Returns true if the app has declared in its manifest that it wants its split APKs to be + /// loaded into isolated Contexts, with their own ClassLoaders and Resources objects. + /// @hide + /// + Future requestsIsolatedSplitLoading() => + _target.method('requestsIsolatedSplitLoading').invoke(); + + /// @hide + ApplicationInfo get applicationInfo => + ApplicationInfo(_target.method('getApplicationInfo'), _classTarget); + + Future setCodePath(String codePath) => + _target.method('setCodePath', arguments: [codePath]).invoke(); + + Future setBaseCodePath(String baseCodePath) => + _target.method('setCodePath', arguments: [baseCodePath]).invoke(); + + Future setSplitCodePaths(List splitCodePaths) => _target + .method('setSplitCodePaths', arguments: [splitCodePaths]).invoke(); + + Future setResourcePath(String resourcePath) => _target + .method('setResourcePath', arguments: [resourcePath]).invoke(); + + Future setBaseResourcePath(String baseResourcePath) => + _target.method('setBaseResourcePath', + arguments: [baseResourcePath]).invoke(); + + Future setSplitResourcePaths(List splitResourcePaths) => + _target.method('setSplitResourcePaths', + arguments: [splitResourcePaths]).invoke(); + + Future get codePath => _target.method('getCodePath').invoke(); + + Future get baseCodePath => + _target.method('getBaseCodePath').invoke(); + + Future> get splitCodePaths => + _target.method('getSplitCodePaths').invoke>(); + + Future get resourcePath => + _target.method('getResourcePath').invoke(); + + Future get baseResourcePath => + _target.method('getBaseResourcePath').invoke(); + + Future> get splitResourcePaths => + _target.method('getSplitResourcePaths').invoke>(); +} diff --git a/lib/src/android/asset_manager.dart b/lib/src/android/asset_manager.dart new file mode 100644 index 0000000..cb5fd14 --- /dev/null +++ b/lib/src/android/asset_manager.dart @@ -0,0 +1,29 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class AssetManager { + AssetManager(this._target); + + factory AssetManager.from(NativeTarget target) => AssetManager(target); + + /// Return a global shared asset manager that provides access to only + /// system assets (no application assets). + /// @hide + factory AssetManager.system(NativeTarget classTarget) => + AssetManager(classTarget.method('getSystem')); + + static final classTarget = + NativeRuntime().classNamed('android.content.res.AssetManager'); + + final NativeTarget _target; + + /// Ensures that the native implementation has not been destroyed. + /// The AssetManager may have been closed, but references to it still exist + /// and therefore the native implementation is not destroyed. + Future ensureValidLocked() => + _target.method('ensureValidLocked').invoke(); + + /// Ensures that the AssetManager has not been explicitly closed. If this method passes, + /// then this implies that ensureValidLocked() also passes. + Future ensureOpenLocked() => + _target.method('ensureOpenLocked').invoke(); +} diff --git a/lib/src/android/build.dart b/lib/src/android/build.dart new file mode 100644 index 0000000..08835d1 --- /dev/null +++ b/lib/src/android/build.dart @@ -0,0 +1,235 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class Build { + Build(this._classTarget); + + factory Build.system() => Build(classTarget); + + static final classTarget = NativeRuntime().classNamed('android.os.Build'); + + final NativeTarget _classTarget; + + Future get tag => _classTarget.memberVariable('TAG').get(); + + Future get unknown => + _classTarget.memberVariable('UNKNOWN').get(); + + Future get id => _classTarget.memberVariable('ID').get(); + + Future get display => + _classTarget.memberVariable('DISPLAY').get(); + + Future get product => + _classTarget.memberVariable('PRODUCT').get(); + + Future get device => + _classTarget.memberVariable('DEVICE').get(); + + Future get board => + _classTarget.memberVariable('BOARD').get(); + + Future get cpuAbi => + _classTarget.memberVariable('CPU_ABI').get(); + + Future get cpuAbi2 => + _classTarget.memberVariable('CPU_ABI2').get(); + + Future get manufacturer => + _classTarget.memberVariable('MANUFACTURER').get(); + + Future get brand => + _classTarget.memberVariable('BRAND').get(); + + Future get model => + _classTarget.memberVariable('MODEL').get(); + + Future get bootloader => + _classTarget.memberVariable('BOOTLOADER').get(); + + Future get radio => + _classTarget.memberVariable('RADIO').get(); + + Future get hardware => + _classTarget.memberVariable('HARDWARE').get(); + + Future get isEmulator => + _classTarget.memberVariable('IS_EMULATOR').get(); + + Future get serial => + _classTarget.method('getSerial').invoke(); + + Future> get supportedAbis => + _classTarget.memberVariable('SUPPORTED_ABIS').get>(); + + Future> get supported32BitAbis => + _classTarget.memberVariable('SUPPORTED_32_BIT_ABIS').get>(); + + Future> get supported64BitAbis => + _classTarget.memberVariable('SUPPORTED_64_BIT_ABIS').get>(); + + Future get type => _classTarget.memberVariable('TYPE').get(); + + Future get tags => _classTarget.memberVariable('TAGS').get(); + + Future get fingerprint => + _classTarget.memberVariable('FINGERPRINT').get(); + + Future get isTrebleEnabled => + _classTarget.memberVariable('IS_TREBLE_ENABLED').get(); + + Future get time => _classTarget.memberVariable('TIME').get(); + + Future get user => _classTarget.memberVariable('USER').get(); + + Future get host => _classTarget.memberVariable('HOST').get(); + + Future get isDebuggable => + _classTarget.memberVariable('IS_DEBUGGABLE').get(); + + Future get isEnglish => + _classTarget.memberVariable('IS_ENG').get(); + + Future get isUserDebug => + _classTarget.memberVariable('IS_USERDEBUG').get(); + + Future get isUser => _classTarget.memberVariable('IS_USER').get(); + + Future get isContainer => + _classTarget.memberVariable('IS_CONTAINER').get(); + + Future get isPermissionReviewRequired => + _classTarget.memberVariable('PERMISSIONS_REVIEW_REQUIRED').get(); + + Future get radioVersion => + _classTarget.method('getRadioVersion').invoke(); +} + +class Version { + Version(this._classTarget); + + factory Version.system() => Version(classTarget); + + static final classTarget = + NativeRuntime().classNamed('android.os.Build.VERSION'); + + final NativeTarget _classTarget; + + Future get incremental => + _classTarget.memberVariable('INCREMENTAL').get(); + + Future get release => + _classTarget.memberVariable('RELEASE').get(); + + Future get baseOperatingSystem => + _classTarget.memberVariable('BASE_OS').get(); + + Future get securityPatch => + _classTarget.memberVariable('SECURITY_PATCH').get(); + + Future get sdk => _classTarget.memberVariable('SDK').get(); + + Future get sdkIntValue => + _classTarget.memberVariable('SDK_INT').get(); + + Future get firstSdkIntValue => + _classTarget.memberVariable('FIRST_SDK_INT').get(); + + Future get previewSdk => + _classTarget.memberVariable('PREVIEW_SDK_INT').get(); + + Future get codeName => + _classTarget.memberVariable('CODENAME').get(); + + Future> get allCodeNames => + _classTarget.memberVariable('ALL_CODENAMES').get>(); + + Future> get activeCodeNames => + _classTarget.memberVariable('ACTIVE_CODENAMES').get>(); + + Future get minSupportedTargetSdk => + _classTarget.memberVariable('MIN_SUPPORTED_TARGET_SDK_INT').get(); +} + +class VersionCodes { + VersionCodes(this._classTarget); + + factory VersionCodes.system() => VersionCodes(classTarget); + + static final classTarget = + NativeRuntime().classNamed('android.os.Build.VERSION_CODES'); + + final NativeTarget _classTarget; + + Future get currentDevelopment => + _classTarget.memberVariable('CUR_DEVELOPMENT').get(); + + Future get base => _classTarget.memberVariable('BASE').get(); + + Future get base1_1 => _classTarget.memberVariable('BASE_1_1').get(); + + Future get cupcake => _classTarget.memberVariable('CUPCAKE').get(); + + Future get donut => _classTarget.memberVariable('DONUT').get(); + + Future get eclair => _classTarget.memberVariable('ECLAIR').get(); + + Future get eclair0_1 => + _classTarget.memberVariable('ECLAIR_0_1').get(); + + Future get eclairMr1 => + _classTarget.memberVariable('ECLAIR_MR1').get(); + + Future get froyo => _classTarget.memberVariable('FROYO').get(); + + Future get gingerbread => + _classTarget.memberVariable('GINGERBREAD').get(); + + Future get homeyComb => + _classTarget.memberVariable('HONEYCOMB').get(); + + Future get homeyCombMr1 => + _classTarget.memberVariable('HONEYCOMB_MR1').get(); + + Future get homeyCombMr2 => + _classTarget.memberVariable('HONEYCOMB_MR2').get(); + + Future get iceCreamSandwich => + _classTarget.memberVariable('ICE_CREAM_SANDWICH').get(); + + Future get iceCreamSandwichMr1 => + _classTarget.memberVariable('ICE_CREAM_SANDWICH_MR1').get(); + + Future get jellyBean => + _classTarget.memberVariable('JELLY_BEAN').get(); + + Future get jellyBeanMr1 => + _classTarget.memberVariable('JELLY_BEAN_MR1').get(); + + Future get jellyBeanMr2 => + _classTarget.memberVariable('JELLY_BEAN_MR2').get(); + + Future get kitKat => _classTarget.memberVariable('KITKAT').get(); + + Future get kitKatWatch => + _classTarget.memberVariable('KITKAT_WATCH').get(); + + Future get l => _classTarget.memberVariable('L').get(); + + Future get lollipop => + _classTarget.memberVariable('LOLLIPOP').get(); + + Future get lollipopMr1 => + _classTarget.memberVariable('LOLLIPOP_MR1').get(); + + Future get m => _classTarget.memberVariable('M').get(); + + Future get n => _classTarget.memberVariable('N').get(); + + Future get nMr1 => _classTarget.memberVariable('N_MR1').get(); + + Future get o => _classTarget.memberVariable('O').get(); + + Future get oMr1 => _classTarget.memberVariable('O_MR1').get(); + + Future get p => _classTarget.memberVariable('P').get(); +} diff --git a/lib/src/android/class_loader.dart b/lib/src/android/class_loader.dart new file mode 100644 index 0000000..94daf66 --- /dev/null +++ b/lib/src/android/class_loader.dart @@ -0,0 +1,22 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class ClassLoader { + ClassLoader(this._target, this._classTarget); + + factory ClassLoader.from(NativeTarget target) => + ClassLoader(target, classTarget); + + static final classTarget = + NativeRuntime().classNamed('java.lang.ClassLoader'); + + final NativeTarget _target; + final NativeTarget _classTarget; + + Future get registerAsParallelCapable => + _classTarget.method('registerAsParallelCapable').invoke(); + + Future resource(String name) => _target + .method('getResource', arguments: [name]) + .method('toString') + .invoke(); +} diff --git a/lib/src/android/context.dart b/lib/src/android/context.dart new file mode 100644 index 0000000..8824a37 --- /dev/null +++ b/lib/src/android/context.dart @@ -0,0 +1,927 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +import 'application_info.dart'; +import 'asset_manager.dart'; +import 'resources.dart'; +import 'shared_preference.dart'; + +class Context { + Context(this._target); + + factory Context.global() => Context(globalTarget); + + static final globalTarget = + NativeRuntime().instanceNamed('Registrar').property('context'); + + final NativeTarget _target; + + /// Returns an AssetManager target for the application's package. + /// + /// @return an AssetManager instance for the application's package + /// @see #getResources() + /// + AssetManager get assets => AssetManager.from(_target.method('getAssets')); + + /// Returns a Resources target for the application's package. + /// + /// @return a Resources instance for the application's package + /// @see #getAssets() + /// + Resources get resources => Resources.from(_target.method('getResources')); + + /// Return PackageManager target to find global package information. */ + NativeTarget get packageManager => _target.method('getPackageManager'); + + /// Return a ContentResolver target for your application's package. */ + NativeTarget get contentResolver => _target.method('getContentResolver'); + + /// Return the Looper target for the main thread of the current process. This is + /// the thread used to dispatch calls to application components (activities, + /// services, etc). + /// + /// @return The main looper. + /// + NativeTarget get mainLooper => _target.method('getMainLooper'); + + /// Return an {@link Executor} that will run enqueued tasks on the main + /// thread associated with this context. This is the thread used to dispatch + /// calls to application components (activities, services, etc). + /// + NativeTarget get mainExecutor => _target.method('getMainExecutor'); + + /// Return the context of the single, global Application object of the + /// current process. This generally should only be used if you need a + /// Context whose lifecycle is separate from the current context, that is + /// tied to the lifetime of the process rather than the current component. + /// + NativeTarget get applicationContext => + _target.method('getApplicationContext'); + + /// Return a localized, styled CharSequence from the application's package's + /// default string table. + /// + /// @param resId Resource id for the CharSequence text + /// + Future text(int resourceId) async => + _target.method('getText', arguments: [resourceId]).invoke(); + + /// Returns a localized string from the application's package's + /// default string table. + /// + /// @param resId Resource id for the string + /// @return The string data associated with the resource, stripped of styled + /// text information. + /// + Future string(int resourceId) => + _target.method('getString', arguments: [resourceId]).invoke(); + + /// Returns a localized formatted string from the application's package's + /// default string table, substituting the format arguments as defined in + /// {@link java.util.Formatter} and {@link java.lang.String#format}. + /// + /// @param resId Resource id for the format string + /// @param formatArgs The format arguments that will be used for + /// substitution. + /// @return The string data associated with the resource, formatted and + /// stripped of styled text information. + /// + Future stringWithFromat(int resourceId, List formatArgs) { + final arguments = [resourceId]; + arguments.addAll(formatArgs); + + return _target.method('getString', arguments: arguments).invoke(); + } + + /// Returns a color associated with a particular resource ID and styled for + /// the current theme. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @return A single color value in the form 0xAARRGGBB. + /// @throws android.content.res.Resources.NotFoundException if the given ID + /// does not exist. + /// + Future color(int resourceId) => + _target.method('getColor', arguments: [resourceId]).invoke(); + + /// Returns a drawable target associated with a particular resource ID and + /// styled for the current theme. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @return An object that can be used to draw this resource. + /// @throws android.content.res.Resources.NotFoundException if the given ID + /// does not exist. + /// + NativeTarget drawable(int resourceId) => + _target.method('getDrawable', arguments: [resourceId]); + + /// Returns a ColorStateList target associated with a particular resource ID and + /// styled for the current theme. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @return A color state list. + /// @throws android.content.res.Resources.NotFoundException if the given ID + /// does not exist. + /// + NativeTarget colorStateList(int resourceId) => + _target.method('getColorStateList', arguments: [resourceId]); + + /// Set the base theme for this context. Note that this should be called + /// before any views are instantiated in the Context (for example before + /// calling {@link android.app.Activity#setContentView} or + /// {@link android.view.LayoutInflater#inflate}). + /// + /// @param resid The style resource describing the theme. + /// + Future setTheme(int resourceId) => + _target.method('setTheme', arguments: [resourceId]).invoke(); + + /// @hide Needed for some internal implementation... not public because + /// you can't assume this actually means anything. */ + Future themeResId() => _target.method('getThemeResId').invoke(); + + /// Return the Theme target associated with this Context. + /// + NativeTarget get theme => _target.method('getTheme'); + + /// Return a class loader you can use to retrieve classes in this package. + /// + NativeTarget get classLoader => _target.method('getClassLoader'); + + /// Return the name of this application's package. */ + Future get packageName => + _target.method('getPackageName').invoke(); + + /// @hide Return the name of the base context this context is derived from. */ + Future get basePackageName => + _target.method('getBasePackageName').invoke(); + + /// @hide Return the package name that should be used for app ops calls from + /// this context. This is the same as {@link #getBasePackageName()} except in + /// cases where system components are loaded into other app processes, in which + /// case this will be the name of the primary package in that process (so that app + /// ops uid verification will work with the name). */ + Future get opPackageName => + _target.method('getOpPackageName').invoke(); + + /// Return the full application info for this context's package. */ + ApplicationInfo get applicationInfo => + ApplicationInfo.from(_target.method('getApplicationInfo')); + + /// Return the full path to this context's primary Android package. + /// The Android package is a ZIP file which contains the application's + /// primary resources. + /// + ///

Note: this is not generally useful for applications, since they should + /// not be directly accessing the file system. + /// + /// @return String Path to the resources. + /// + Future get packageResourcePath => + _target.method('getPackageResourcePath').invoke(); + + /// Return the full path to this context's primary Android package. + /// The Android package is a ZIP file which contains application's + /// primary code and assets. + /// + ///

Note: this is not generally useful for applications, since they should + /// not be directly accessing the file system. + /// + /// @return String Path to the code and assets. + /// + Future get packageCodePath => + _target.method('getPackageCodePath').invoke(); + + /// @hide + /// @deprecated use {@link #getSharedPreferencesPath(String)} + /// + NativeTarget sharedPrefsFile(String name) => + _target.method('getSharedPrefsFile', arguments: [name]); + + /// Retrieve and hold the contents of the preferences file 'name', returning + /// a SharedPreferences through which you can retrieve and modify its + /// values. Only one instance of the SharedPreferences object is returned + /// to any callers for the same name, meaning they will see each other's + /// edits as soon as they are made. + /// + /// This method is thead-safe. + /// + /// @param name Desired preferences file. If a preferences file by this name + /// does not exist, it will be created when you retrieve an + /// editor (SharedPreferences.edit()) and then commit changes (Editor.commit()). + /// @param mode Operating mode. + /// + /// @return The single {@link SharedPreferences} instance that can be used + /// to retrieve and modify the preference values. + /// + /// @see #MODE_PRIVATE + /// + SharedPreferences sharedPreferences(String name, int mode) => + SharedPreferences( + _target.method('getSharedPreferences', arguments: [name, mode])); + + /// Delete an existing shared preferences file. + /// + /// @param name The name (unique in the application package) of the shared + /// preferences file. + /// @return {@code true} if the shared preferences file was successfully + /// deleted; else {@code false}. + /// @see #getSharedPreferences(String, int) + /// + Future deleteSharedPreferences(String name) => _target + .method('deleteSharedPreferences', arguments: [name]).invoke(); + + /// @hide */ + Future reloadSharedPreferences() => + _target.method('reloadSharedPreferences').invoke(); + + /// Delete the given private file associated with this Context's + /// application package. + /// + /// @param name The name of the file to delete; can not contain path + /// separators. + /// + /// @return {@code true} if the file was successfully deleted; else + /// {@code false}. + /// + /// @see #openFileInput + /// @see #openFileOutput + /// @see #fileList + /// @see java.io.File#delete() + /// + Future deleteFile(String name) => + _target.method('deleteFile', arguments: [name]).invoke(); + + /// Returns the absolute path to the directory on the filesystem where all + /// private files belonging to this app are stored. Apps should not use this + /// path directly; they should instead use {@link #getFilesDir()}, + /// {@link #getCacheDir()}, {@link #getDir(String, int)}, or other storage + /// APIs on this class. + /// + /// @see ApplicationInfo#dataDir + /// + NativeTarget get dataDir => _target.method('getDataDir'); + + /// Returns the absolute path to the directory on the filesystem where files + /// created with {@link #openFileOutput} are stored. + /// + /// @return The path of the directory holding application files. + /// @see #openFileOutput + /// @see #getFileStreamPath + /// @see #getDir + /// + NativeTarget get filesDir => _target.method('getFilesDir'); + + /// Returns the absolute path to the directory on the filesystem similar to + /// {@link #getFilesDir()}. The difference is that files placed under this + /// directory will be excluded from automatic backup to remote storage. See + /// {@link android.app.backup.BackupAgent BackupAgent} for a full discussion + /// of the automatic backup mechanism in Android. + /// + /// @return The path of the directory holding application files that will not + /// be automatically backed up to remote storage. + /// @see #openFileOutput + /// @see #getFileStreamPath + /// @see #getDir + /// @see android.app.backup.BackupAgent + /// + NativeTarget get noBackupFilesDir => _target.method('getNoBackupFilesDir'); + + /// Returns the absolute path to the directory on the primary shared/external + /// storage device where the application can place persistent files it owns. + /// These files are internal to the applications, and not typically visible + /// to the user as media. + /// + /// @param type The type of files directory to return. May be {@code null} + /// for the root of the files directory or one of the following + /// constants for a subdirectory: + /// {@link android.os.Environment#DIRECTORY_MUSIC}, + /// {@link android.os.Environment#DIRECTORY_PODCASTS}, + /// {@link android.os.Environment#DIRECTORY_RINGTONES}, + /// {@link android.os.Environment#DIRECTORY_ALARMS}, + /// {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, + /// {@link android.os.Environment#DIRECTORY_PICTURES}, or + /// {@link android.os.Environment#DIRECTORY_MOVIES}. + /// @return the absolute path to application-specific directory. May return + /// {@code null} if shared storage is not currently available. + /// @see #getFilesDir + /// @see #getExternalFilesDirs(String) + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget externalFilesDir(String type) => + _target.method('getExternalFilesDir', arguments: [type]); + + /// Returns absolute paths to application-specific directories on all + /// shared/external storage devices where the application can place + /// persistent files it owns. These files are internal to the application, + /// and not typically visible to the user as media. + /// + /// @param type The type of files directory to return. May be {@code null} + /// for the root of the files directory or one of the following + /// constants for a subdirectory: + /// {@link android.os.Environment#DIRECTORY_MUSIC}, + /// {@link android.os.Environment#DIRECTORY_PODCASTS}, + /// {@link android.os.Environment#DIRECTORY_RINGTONES}, + /// {@link android.os.Environment#DIRECTORY_ALARMS}, + /// {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, + /// {@link android.os.Environment#DIRECTORY_PICTURES}, or + /// {@link android.os.Environment#DIRECTORY_MOVIES}. + /// @return the absolute paths to application-specific directories. Some + /// individual paths may be {@code null} if that shared storage is + /// not currently available. The first path returned is the same as + /// {@link #getExternalFilesDir(String)}. + /// @see #getExternalFilesDir(String) + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget externalFilesDirs(String type) => + _target.method('getExternalFilesDirs', arguments: [type]); + + /// Return the primary shared/external storage directory where this + /// application's OBB files (if there are any) can be found. Note if the + /// application does not have any OBB files, this directory may not exist. + /// + /// @return the absolute path to application-specific directory. May return + /// {@code null} if shared storage is not currently available. + /// @see #getObbDirs() + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget get obbDir => _target.method('getObbDir'); + + /// Returns absolute paths to application-specific directories on all + /// shared/external storage devices where the application's OBB files (if + /// there are any) can be found. Note if the application does not have any + /// OBB files, these directories may not exist. + /// + /// @return the absolute paths to application-specific directories. Some + /// individual paths may be {@code null} if that shared storage is + /// not currently available. The first path returned is the same as + /// {@link #getObbDir()} + /// @see #getObbDir() + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget get obbDirs => _target.method('getObbDirs'); + + /// Returns the absolute path to the application specific cache directory on + /// the filesystem. + /// + /// @return The path of the directory holding application cache files. + /// @see #openFileOutput + /// @see #getFileStreamPath + /// @see #getDir + /// @see #getExternalCacheDir + /// + NativeTarget get cacheDir => _target.method('getCacheDir'); + + /// Returns the absolute path to the application specific cache directory on + /// the filesystem designed for storing cached code. + /// + /// @return The path of the directory holding application code cache files. + /// + NativeTarget get codeCacheDir => _target.method('getCodeCacheDir'); + + /// Returns absolute path to application-specific directory on the primary + /// shared/external storage device where the application can place cache + /// files it owns. These files are internal to the application, and not + /// typically visible to the user as media. + /// + /// @return the absolute path to application-specific directory. May return + /// {@code null} if shared storage is not currently available. + /// @see #getCacheDir + /// @see #getExternalCacheDirs() + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget get externalCacheDir => _target.method('getExternalCacheDir'); + + /// Returns absolute path to application-specific directory in the preloaded cache. + ///

Files stored in the cache directory can be deleted when the device runs low on storage. + /// There is no guarantee when these files will be deleted. + /// @hide + /// + NativeTarget get preloadsFileCache => _target.method('getPreloadsFileCache'); + + /// Returns absolute paths to application-specific directories on all + /// shared/external storage devices where the application can place cache + /// files it owns. These files are internal to the application, and not + /// typically visible to the user as media. + /// + /// @return the absolute paths to application-specific directories. Some + /// individual paths may be {@code null} if that shared storage is + /// not currently available. The first path returned is the same as + /// {@link #getExternalCacheDir()}. + /// @see #getExternalCacheDir() + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget get externalCacheDirs => _target.method('getExternalCacheDirs'); + + /// Returns absolute paths to application-specific directories on all + /// shared/external storage devices where the application can place media + /// files. These files are scanned and made available to other apps through + /// {@link MediaStore}. + /// + /// @return the absolute paths to application-specific directories. Some + /// individual paths may be {@code null} if that shared storage is + /// not currently available. + /// @see Environment#getExternalStorageState(File) + /// @see Environment#isExternalStorageEmulated(File) + /// @see Environment#isExternalStorageRemovable(File) + /// + NativeTarget get externalMediaDirs => _target.method('getExternalMediaDirs'); + + /// Returns an array of strings naming the private files associated with + /// this Context's application package. + /// + /// @return Array of strings naming the private files. + /// + /// @see #openFileInput + /// @see #openFileOutput + /// @see #deleteFile + /// + Future> get fileList => + _target.method('fileList').invoke>(); + + /// Delete an existing private SQLiteDatabase associated with this Context's + /// application package. + /// + /// @param name The name (unique in the application package) of the + /// database. + /// + /// @return {@code true} if the database was successfully deleted; else {@code false}. + /// + /// @see #openOrCreateDatabase + /// + Future deleteDatabase(String name) => + _target.method('deleteDatabase', arguments: [name]).invoke(); + + /// Returns the absolute path on the filesystem where a database created with + /// {@link #openOrCreateDatabase} is stored. + ///

+ /// The returned path may change over time if the calling app is moved to an + /// adopted storage device, so only relative paths should be persisted. + /// + /// @param name The name of the database for which you would like to get + /// its path. + /// + /// @return An absolute path to the given database. + /// + /// @see #openOrCreateDatabase + /// + NativeTarget databasePath(String name) => + _target.method('getDatabasePath', arguments: [name]); + + /// Returns an array of strings naming the private databases associated with + /// this Context's application package. + /// + /// @return Array of strings naming the private databases. + /// + /// @see #openOrCreateDatabase + /// @see #deleteDatabase + /// + Future> get databaseList => + _target.method('databaseList').invoke>(); + + /// @deprecated Use {@link android.app.WallpaperManager#getDrawable + /// WallpaperManager.get()} instead. + /// + NativeTarget get wallpaper => _target.method('getWallpaper'); + + /// @deprecated Use {@link android.app.WallpaperManager#peekDrawable + /// WallpaperManager.peek()} instead. + /// + NativeTarget get peekWallpaper => _target.method('peekWallpaper'); + + /// @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumWidth() + /// WallpaperManager.getDesiredMinimumWidth()} instead. + /// + Future get wallpaperDesiredMinimumWidth => + _target.method('getWallpaperDesiredMinimumWidth').invoke(); + + /// @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumHeight() + /// WallpaperManager.getDesiredMinimumHeight()} instead. + /// + Future get wallpaperDesiredMinimumHeight => + _target.method('getWallpaperDesiredMinimumHeight').invoke(); + + /// @deprecated Use {@link android.app.WallpaperManager#clear + /// WallpaperManager.clear()} instead. + ///

This method requires the caller to hold the permission + /// {@link android.Manifest.permission#SET_WALLPAPER}. + /// + Future clearWallpaper() => + _target.method('clearWallpaper').invoke(); + + /// Identifies whether this Context instance will be able to process calls to + /// {@link #startActivityForResult(String, Intent, int, Bundle)}. + /// @hide + /// + Future get canStartActivityForResult => + _target.method('canStartActivityForResult').invoke(); + + /// Return the handle to a system-level service by name. The class of the + /// returned object varies by the requested name. Currently available names + /// + /// @param name The name of the desired service. + /// + /// @return The service or null if the name does not exist. + /// + /// + NativeTarget systemService(String name) => + _target.method('getSystemService', arguments: [name]); + + /// Determine whether the given permission is allowed for a particular + /// process and user ID running in the system. + /// + /// @param permission The name of the permission being checked. + /// @param pid The process ID being checked against. Must be > 0. + /// @param uid The user ID being checked against. A uid of 0 is the root + /// user, which will pass every permission check. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the given + /// pid/uid is allowed that permission, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + /// @see PackageManager#checkPermission(String, String) + /// @see #checkCallingPermission + /// + Future checkPermission(String permission, int pid, int uid) => + _target.method('checkPermission', + arguments: [permission, pid, uid]).invoke(); + + /// Determine whether the calling process of an IPC you are handling has been + /// granted a particular permission. This is basically the same as calling + /// {@link #checkPermission(String, int, int)} with the pid and uid returned + /// by {@link android.os.Binder#getCallingPid} and + /// {@link android.os.Binder#getCallingUid}. One important difference + /// is that if you are not currently processing an IPC, this function + /// will always fail. This is done to protect against accidentally + /// leaking permissions; you can use {@link #checkCallingOrSelfPermission} + /// to avoid this protection. + /// + /// @param permission The name of the permission being checked. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the calling + /// pid/uid is allowed that permission, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + /// @see PackageManager#checkPermission(String, String) + /// @see #checkPermission + /// @see #checkCallingOrSelfPermission + /// + Future checkCallingPermission(String permission) => _target + .method('checkCallingPermission', arguments: [permission]).invoke(); + + /// Determine whether the calling process of an IPC or you have been + /// granted a particular permission. This is the same as + /// {@link #checkCallingPermission}, except it grants your own permissions + /// if you are not currently processing an IPC. Use with care! + /// + /// @param permission The name of the permission being checked. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the calling + /// pid/uid is allowed that permission, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + /// @see PackageManager#checkPermission(String, String) + /// @see #checkPermission + /// @see #checkCallingPermission + /// + Future checkCallingOrSelfPermission(String permission) => + _target.method('checkCallingOrSelfPermission', + arguments: [permission]).invoke(); + + /// Determine whether you have been granted a particular permission. + /// + /// @param permission The name of the permission being checked. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if you have the + /// permission, or {@link PackageManager#PERMISSION_DENIED} if not. + /// + /// @see PackageManager#checkPermission(String, String) + /// @see #checkCallingPermission(String) + /// + Future checkSelfPermission(String permission) => _target + .method('checkSelfPermission', arguments: [permission]).invoke(); + + /// If the given permission is not allowed for a particular process + /// and user ID running in the system, throw a {@link SecurityException}. + /// + /// @param permission The name of the permission being checked. + /// @param pid The process ID being checked against. Must be > 0. + /// @param uid The user ID being checked against. A uid of 0 is the root + /// user, which will pass every permission check. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkPermission(String, int, int) + /// + Future enforcePermission( + String permission, int pid, int uid, String message) => + _target.method('enforcePermission', + arguments: [permission, pid, uid, message]).invoke(); + + /// If the calling process of an IPC you are handling has not been + /// granted a particular permission, throw a {@link + /// SecurityException}. This is basically the same as calling + /// {@link #enforcePermission(String, int, int, String)} with the + /// pid and uid returned by {@link android.os.Binder#getCallingPid} + /// and {@link android.os.Binder#getCallingUid}. One important + /// difference is that if you are not currently processing an IPC, + /// this function will always throw the SecurityException. This is + /// done to protect against accidentally leaking permissions; you + /// can use {@link #enforceCallingOrSelfPermission} to avoid this + /// protection. + /// + /// @param permission The name of the permission being checked. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkCallingPermission(String) + /// + Future enforceCallingPermission(String permission, String message) => + _target.method('enforceCallingPermission', + arguments: [permission, message]).invoke(); + + /// If neither you nor the calling process of an IPC you are + /// handling has been granted a particular permission, throw a + /// {@link SecurityException}. This is the same as {@link + /// #enforceCallingPermission}, except it grants your own + /// permissions if you are not currently processing an IPC. Use + /// with care! + /// + /// @param permission The name of the permission being checked. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkCallingOrSelfPermission(String) + /// + Future enforceCallingOrSelfPermission( + String permission, String message) => + _target.method('enforceCallingOrSelfPermission', + arguments: [permission, message]).invoke(); + + /// Grant permission to access a specific Uri to another package, regardless + /// of whether that package has general permission to access the Uri's + /// content provider. This can be used to grant specific, temporary + /// permissions, typically in response to user interaction (such as the + /// user opening an attachment that you would like someone else to + /// display). + /// + /// @param toPackage The package you would like to allow to access the Uri. + /// @param uri The Uri you would like to grant access to. + /// @param modeFlags The desired access modes. + /// + /// @see #revokeUriPermission + /// + Future grantUriPermission(String toPackage, Uri uri, int modeFlags) => + _target.method('grantUriPermission', + arguments: [toPackage, uri, modeFlags]).invoke(); + + /// Remove all permissions to access a particular content provider Uri + /// that were previously added with {@link #grantUriPermission} or any other mechanism. + /// The given Uri will match all previously granted Uris that are the same or a + /// sub-path of the given Uri. That is, revoking "content://foo/target" will + /// revoke both "content://foo/target" and "content://foo/target/sub", but not + /// "content://foo". It will not remove any prefix grants that exist at a + /// higher level. + /// + /// @param uri The Uri you would like to revoke access to. + /// @param modeFlags The access modes to revoke. + /// + /// @see #grantUriPermission + /// + Future revokeUriPermission(String toPackage, int modeFlags, + {Uri uri}) => + _target.method('revokeUriPermission', + arguments: [toPackage, uri, modeFlags]).invoke(); + + /// Determine whether the calling process and user ID has been + /// granted permission to access a specific URI. This is basically + /// the same as calling {@link #checkUriPermission(Uri, int, int, + /// int)} with the pid and uid returned by {@link + /// android.os.Binder#getCallingPid} and {@link + /// android.os.Binder#getCallingUid}. One important difference is + /// that if you are not currently processing an IPC, this function + /// will always fail. + /// + /// @param uri The uri that is being checked. + /// @param modeFlags The access modes to check. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the caller + /// is allowed to access that uri, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + /// @see #checkUriPermission(Uri, int, int, int) + /// + Future checkCallingUriPermission(Uri uri, int modeFlags) => + _target.method('checkCallingUriPermission', + arguments: [uri, modeFlags]).invoke(); + + /// Determine whether the calling process of an IPC or you has been granted + /// permission to access a specific URI. This is the same as + /// {@link #checkCallingUriPermission}, except it grants your own permissions + /// if you are not currently processing an IPC. Use with care! + /// + /// @param uri The uri that is being checked. + /// @param modeFlags The access modes to check. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the caller + /// is allowed to access that uri, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + /// @see #checkCallingUriPermission + /// + Future checkCallingOrSelfUriPermission(Uri uri, int modeFlags) => + _target.method('checkCallingOrSelfUriPermission', + arguments: [uri, modeFlags]).invoke(); + + /// Check both a Uri and normal permission. This allows you to perform + /// both {@link #checkPermission} and {@link #checkUriPermission} in one + /// call. + /// + /// @param uri The Uri whose permission is to be checked, or null to not + /// do this check. + /// @param readPermission The permission that provides overall read access, + /// or null to not do this check. + /// @param writePermission The permission that provides overall write + /// access, or null to not do this check. + /// @param pid The process ID being checked against. Must be > 0. + /// @param uid The user ID being checked against. A uid of 0 is the root + /// user, which will pass every permission check. + /// @param modeFlags The access modes to check. + /// + /// @return {@link PackageManager#PERMISSION_GRANTED} if the caller + /// is allowed to access that uri or holds one of the given permissions, or + /// {@link PackageManager#PERMISSION_DENIED} if it is not. + /// + Future checkUriPermission(Uri uri, int pid, int uid, int modeFlags, + {String readPermission, String writePermission}) => + _target.method('checkUriPermission', arguments: [ + uri, + readPermission, + writePermission, + pid, + uid, + modeFlags + ]).invoke(); + + /// If the calling process and user ID has not been granted + /// permission to access a specific URI, throw {@link + /// SecurityException}. This is basically the same as calling + /// {@link #enforceUriPermission(Uri, int, int, int, String)} with + /// the pid and uid returned by {@link + /// android.os.Binder#getCallingPid} and {@link + /// android.os.Binder#getCallingUid}. One important difference is + /// that if you are not currently processing an IPC, this function + /// will always throw a SecurityException. + /// + /// @param uri The uri that is being checked. + /// @param modeFlags The access modes to enforce. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkCallingUriPermission(Uri, int) + /// + Future enforceCallingUriPermission( + Uri uri, int modeFlags, String message) => + _target.method('enforceCallingUriPermission', + arguments: [uri, modeFlags, message]).invoke(); + + /// If the calling process of an IPC or you has not been + /// granted permission to access a specific URI, throw {@link + /// SecurityException}. This is the same as {@link + /// #enforceCallingUriPermission}, except it grants your own + /// permissions if you are not currently processing an IPC. Use + /// with care! + /// + /// @param uri The uri that is being checked. + /// @param modeFlags The access modes to enforce. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkCallingOrSelfUriPermission(Uri, int) + /// + Future enforceCallingOrSelfUriPermission( + Uri uri, int modeFlags, String message) => + _target.method('enforceCallingOrSelfUriPermission', + arguments: [uri, modeFlags, message]).invoke(); + + /// Enforce both a Uri and normal permission. This allows you to perform + /// both {@link #enforcePermission} and {@link #enforceUriPermission} in one + /// call. + /// + /// @param uri The Uri whose permission is to be checked, or null to not + /// do this check. + /// @param readPermission The permission that provides overall read access, + /// or null to not do this check. + /// @param writePermission The permission that provides overall write + /// access, or null to not do this check. + /// @param pid The process ID being checked against. Must be > 0. + /// @param uid The user ID being checked against. A uid of 0 is the root + /// user, which will pass every permission check. + /// @param modeFlags The access modes to enforce. + /// @param message A message to include in the exception if it is thrown. + /// + /// @see #checkUriPermission(Uri, String, String, int, int, int) + /// + Future enforceUriPermission( + Uri uri, int pid, int uid, int modeFlags, String message, + {String readPermission, String writePermission}) => + _target.method('enforceUriPermission', arguments: [ + uri, + readPermission, + writePermission, + pid, + uid, + modeFlags, + message + ]).invoke(); + + /// Get the user associated with this context + /// @hide + /// + Future get userId => _target.method('getUserId').invoke(); + + /// Gets the display adjustments holder for this context. This information + /// is provided on a per-application or activity basis and is used to simulate lower density + /// display metrics for legacy applications and restricted screen sizes. + /// + /// @param displayId The display id for which to get compatibility info. + /// @return The compatibility info holder, or null if not required by the application. + /// @hide + /// + NativeTarget displayAdjustments(int displayId) => + _target.method('getDisplayAdjustments', arguments: [displayId]); + + /// @hide + /// + NativeTarget get display => _target.method('getDisplay'); + + /// @hide + /// + Future updateDisplay(int displayId) => + _target.method('updateDisplay', arguments: [displayId]).invoke(); + + /// Indicates whether this Context is restricted. + /// + /// @return {@code true} if this Context is restricted, {@code false} otherwise. + /// + /// @see #CONTEXT_RESTRICTED + /// + Future get restricted => _target.method('isRestricted').invoke(); + + /// Indicates if the storage APIs of this Context are backed by + /// device-protected storage. + /// + /// @see #createDeviceProtectedStorageContext() + /// + Future get deviceProtectedStorage => + _target.method('isDeviceProtectedStorage').invoke(); + + /// Indicates if the storage APIs of this Context are backed by + /// credential-protected storage. + /// + /// @see #createCredentialProtectedStorageContext() + /// @hide + /// + Future get credentialProtectedStorage => + _target.method('isCredentialProtectedStorage').invoke(); + + /// Returns true if the context can load unsafe resources, e.g. fonts. + /// @hide + /// + Future get canLoadUnsafeResources => + _target.method('canLoadUnsafeResources').invoke(); + + /// @hide + /// + NativeTarget get activityToken => _target.method('getActivityToken'); + + /// @hide + /// + Future get autofillCompatibilityEnabled => + _target.method('isAutofillCompatibilityEnabled').invoke(); + + /// @hide + /// + Future setAutofillCompatibilityEnabled({bool autofillCompatEnabled}) => + _target.method('setAutofillCompatibilityEnabled', + arguments: [autofillCompatEnabled]).invoke(); + + /// Throws an exception if the Context is using system resources, + /// which are non-runtime-overlay-themable and may show inconsistent UI. + /// @hide + /// + Future assertRuntimeOverlayThemable() => + _target.method('assertRuntimeOverlayThemable').invoke(); +} diff --git a/lib/src/android/resources.dart b/lib/src/android/resources.dart new file mode 100644 index 0000000..70ed759 --- /dev/null +++ b/lib/src/android/resources.dart @@ -0,0 +1,463 @@ +import 'dart:core'; + +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +import 'asset_manager.dart'; +import 'class_loader.dart'; +import 'resources_impl.dart'; + +class Resources { + Resources(this._target, this._classTarget); + + /// + /// Return a global shared Resources object that provides access to only + /// system resources (no application resources), and is not configured for + /// the current screen (can not use dimension units, does not change based + /// on orientation, etc). + /// + factory Resources.system() => Resources.from(classTarget.method('getSystem')); + + factory Resources.from(NativeTarget target) => Resources(target, classTarget); + + static final classTarget = + NativeRuntime().classNamed('android.content.res.Resources'); + + final NativeTarget _classTarget; + final NativeTarget _target; + + Future selectDefaultTheme(int curTheme, int targetSdkVersion) => + _classTarget.method('selectDefaultTheme', + arguments: [curTheme, targetSdkVersion]).invoke(); + + /// @hide */ + Future selectSystemTheme(int curTheme, int targetSdkVersion, int orig, + int holo, int dark, int deviceDefault) => + _classTarget.method('selectSystemTheme', arguments: [ + curTheme, + targetSdkVersion, + orig, + holo, + dark, + deviceDefault + ]).invoke(); + + /// + /// @hide + /// + ResourcesImpl get impl => + ResourcesImpl.from(_target.memberVariable('mResourcesImpl')); + + /// + /// @hide + /// + ClassLoader get classLoader => + ClassLoader.from(_target.memberVariable('mClassLoader')); + + /// + /// @hide + /// + Future preloadFonts(int id) => + _target.method('preloadFonts', arguments: [id]).invoke(); + + /// + /// Returns the character sequence necessary for grammatically correct pluralization + /// of the given resource ID for the given quantity. + /// Note that the character sequence is selected based solely on grammatical necessity, + /// and that such rules differ between languages. Do not assume you know which string + /// will be returned for a given quantity. See + /// String Resources + /// for more detail. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @param quantity The number used to get the correct string for the current language's + /// plural rules. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return CharSequence The string data associated with the resource, plus + /// possibly styled text information. + /// + Future quantityText(int id, int quantity) => _target + .method('getQuantityText', arguments: [id, quantity]).invoke(); + + /// + /// Return the string value associated with a particular resource ID. It + /// will be stripped of any styled text information. + /// {@more} + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return String The string data associated with the resource, + /// stripped of styled text information. + /// + Future string(int id) => + _target.method('getString', arguments: [id]).invoke(); + + /// + /// Return the string value associated with a particular resource ID, + /// substituting the format arguments as defined in {@link java.util.Formatter} + /// and {@link java.lang.String#format}. It will be stripped of any styled text + /// information. + /// {@more} + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @param formatArgs The format arguments that will be used for substitution. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return String The string data associated with the resource, + /// stripped of styled text information. + /// + Future stringWithFromat(int id, List formatArgs) { + final arguments = [id]; + arguments.addAll(formatArgs); + return _target.method('getString', arguments: arguments).invoke(); + } + + /// + /// Formats the string necessary for grammatically correct pluralization + /// of the given resource ID for the given quantity, using the given arguments. + /// Note that the string is selected based solely on grammatical necessity, + /// and that such rules differ between languages. Do not assume you know which string + /// will be returned for a given quantity. See + /// String Resources + /// for more detail. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @param quantity The number used to get the correct string for the current language's + /// plural rules. + /// @param formatArgs The format arguments that will be used for substitution. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return String The string data associated with the resource, + /// stripped of styled text information. + /// + Future quantityStringWithFromat( + int id, int quantity, List formatArgs) { + final arguments = [id, quantity]; + arguments.addAll(formatArgs); + return _target + .method('getQuantityString', arguments: arguments) + .invoke(); + } + + /// + /// Returns the string necessary for grammatically correct pluralization + /// of the given resource ID for the given quantity. + /// Note that the string is selected based solely on grammatical necessity, + /// and that such rules differ between languages. Do not assume you know which string + /// will be returned for a given quantity. See + /// String Resources + /// for more detail. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @param quantity The number used to get the correct string for the current language's + /// plural rules. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return String The string data associated with the resource, + /// stripped of styled text information. + /// + Future quantityString(int id, int quantity) => _target + .method('getQuantityString', arguments: [id, quantity]).invoke(); + + /// + /// Return the styled text array associated with a particular resource ID. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return The styled text array associated with the resource. + /// + + Future> stringArray(int id) => + _target.method('getStringArray', arguments: [id]).invoke>(); + + /// + /// Return the int array associated with a particular resource ID. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return The int array associated with the resource. + /// + Future> intArray(int id) => + _target.method('getIntArray', arguments: [id]).invoke>(); + + /// + /// Retrieve a dimensional for a particular resource ID. Unit + /// conversions are based on the current {@link DisplayMetrics} associated + /// with the resources. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @return Resource dimension value multiplied by the appropriate + /// metric. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getDimensionPixelOffset + /// @see #getDimensionPixelSize + /// + Future dimension(int id) => + _target.method('getDimension', arguments: [id]).invoke(); + + /// + /// Retrieve a dimensional for a particular resource ID for use + /// as an offset in raw pixels. This is the same as + /// {@link #getDimension}, except the returned value is converted to + /// integer pixels for you. An offset conversion involves simply + /// truncating the base value to an integer. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @return Resource dimension value multiplied by the appropriate + /// metric and truncated to integer pixels. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getDimension + /// @see #getDimensionPixelSize + /// + Future dimensionPixelOffset(int id) => + _target.method('getDimensionPixelOffset', arguments: [id]).invoke(); + + /// + /// Retrieve a dimensional for a particular resource ID for use + /// as a size in raw pixels. This is the same as + /// {@link #getDimension}, except the returned value is converted to + /// integer pixels for use as a size. A size conversion involves + /// rounding the base value, and ensuring that a non-zero base value + /// is at least one pixel in size. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @return Resource dimension value multiplied by the appropriate + /// metric and truncated to integer pixels. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getDimension + /// @see #getDimensionPixelOffset + /// + Future dimensionPixelSize(int id) => + _target.method('getDimensionPixelSize', arguments: [id]).invoke(); + + /// + /// Retrieve a fractional unit for a particular resource ID. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// @param base The base value of this fraction. In other words, a + /// standard fraction is multiplied by this value. + /// @param pbase The parent base value of this fraction. In other + /// words, a parent fraction (nn%p) is multiplied by this + /// value. + /// + /// @return Attribute fractional value multiplied by the appropriate + /// base value. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + Future fraction(int id, int base, int pbase) => _target + .method('getFraction', arguments: [id, base, pbase]).invoke(); + + /// + /// Returns a color integer associated with a particular resource ID. If the + /// resource holds a complex {@link ColorStateList}, then the default color + /// from the set is returned. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does + /// not exist. + /// + /// @return A single color value in the form 0xAARRGGBB. + /// @deprecated Use {@link #getColor(int, Theme)} instead. + /// + Future color(int id) => + _target.method('getColor', arguments: [id]).invoke(); + + /// + /// Return a boolean associated with a particular resource ID. This can be + /// used with any integral resource value, and will return true if it is + /// non-zero. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return Returns the boolean value contained in the resource. + /// + Future boolean(int id) => + _target.method('getBoolean', arguments: [id]).invoke(); + + /// + /// Return an integer associated with a particular resource ID. + /// + /// @param id The desired resource identifier, as generated by the aapt + /// tool. This integer encodes the package, type, and resource + /// entry. The value 0 is an invalid identifier. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @return Returns the integer value contained in the resource. + /// + Future integer(int id) => + _target.method('getInteger', arguments: [id]).invoke(); + + /// + /// Return a resource identifier for the given resource name. A fully + /// qualified resource name is of the form "package:type/entry". The first + /// two components (package and type) are optional if defType and + /// defPackage, respectively, are specified here. + /// + ///

Note: use of this function is discouraged. It is much more + /// efficient to retrieve resources by identifier than by name. + /// + /// @param name The name of the desired resource. + /// @param defType Optional default resource type to find, if "type/" is + /// not included in the name. Can be null to require an + /// explicit type. + /// @param defPackage Optional default package to find, if "package:" is + /// not included in the name. Can be null to require an + /// explicit package. + /// + /// @return int The associated resource identifier. Returns 0 if no such + /// resource was found. (0 is not a valid resource ID.) + /// + Future dentifier(String name, String defType, String defPackage) => + _target.method('getIdentifier', + arguments: [name, defType, defPackage]).invoke(); + + /// + /// Return true if given resource identifier includes a package. + /// + /// @hide + /// + Future resourceHasPackage(int id) => + _target.method('resourceHasPackage', arguments: [id]).invoke(); + + /// + /// Return the full name for a given resource identifier. This name is + /// a single string of the form "package:type/entry". + /// + /// @param resid The resource identifier whose name is to be retrieved. + /// + /// @return A string holding the name of the resource. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getResourcePackageName + /// @see #getResourceTypeName + /// @see #getResourceEntryName + /// + Future resourceName(int id) => + _target.method('getResourceName', arguments: [id]).invoke(); + + /// + /// Return the package name for a given resource identifier. + /// + /// @param resid The resource identifier whose package name is to be + /// retrieved. + /// + /// @return A string holding the package name of the resource. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getResourceName + /// + Future resourcePackageName(int id) => _target + .method('getResourcePackageName', arguments: [id]).invoke(); + + /// + /// Return the type name for a given resource identifier. + /// + /// @param resid The resource identifier whose type name is to be + /// retrieved. + /// + /// @return A string holding the type name of the resource. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getResourceName + /// + Future resourceTypeName(int id) => + _target.method('getResourceTypeName', arguments: [id]).invoke(); + + /// + /// Return the entry name for a given resource identifier. + /// + /// @param resid The resource identifier whose entry name is to be + /// retrieved. + /// + /// @return A string holding the entry name of the resource. + /// + /// @throws NotFoundException Throws NotFoundException if the given ID does not exist. + /// + /// @see #getResourceName + /// + Future resourceEntryName(int id) => + _target.method('getResourceEntryName', arguments: [id]).invoke(); + + /// + /// Retrieve underlying AssetManager storage for these resources. + /// + AssetManager get assetManager => + AssetManager.from(_target.method('getAssets')); + + /// + /// Call this to remove all cached loaded layout resources from the + /// Resources object. Only intended for use with performance testing + /// tools. + /// + Future flushLayoutCache() => + _target.method('flushLayoutCache').invoke(); + + /// + /// Start preloading of resource data using this Resources object. Only + /// for use by the zygote process for loading common system resources. + /// {@hide} + /// + Future startPreloading() => + _target.method('startPreloading').invoke(); + + /// + /// Called by zygote when it is done preloading resources, to change back + /// to normal Resources operation. + /// + Future finishPreloading() => + _target.method('finishPreloading').invoke(); +} diff --git a/lib/src/android/resources_impl.dart b/lib/src/android/resources_impl.dart new file mode 100644 index 0000000..c3216c2 --- /dev/null +++ b/lib/src/android/resources_impl.dart @@ -0,0 +1,20 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +import 'asset_manager.dart'; + +class ResourcesImpl { + ResourcesImpl(this._target, this._classTarget); + + factory ResourcesImpl.from(NativeTarget target) => + ResourcesImpl(target, classTarget); + + static final classTarget = NativeRuntime().classNamed('ResourcesImp'); + + final NativeTarget _target; + final NativeTarget _classTarget; + + AssetManager get assets => AssetManager.from(_target.method('getAssets')); + + Future attrForQuantityCode(String quantityCode) => _classTarget + .method('attrForQuantityCode', arguments: [quantityCode]).invoke(); +} diff --git a/lib/src/android/shared_preference.dart b/lib/src/android/shared_preference.dart new file mode 100644 index 0000000..2aa5ad5 --- /dev/null +++ b/lib/src/android/shared_preference.dart @@ -0,0 +1,259 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class Editor { + Editor._(this._target); + + final NativeTarget _target; + + /// + /// Set a String value in the preferences editor, to be written back once + /// {@link #commit} or {@link #apply} are called. + /// + /// @param key The name of the preference to modify. + /// @param value The new value for the preference. Passing {@code null} + /// for this argument is equivalent to calling {@link #remove(String)} with + /// this key. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor putString(String key, String value) => + Editor._(_target.method('putString', arguments: [key, value])); + + /// + /// Set a set of String values in the preferences editor, to be written + /// back once {@link #commit} or {@link #apply} is called. + /// + /// @param key The name of the preference to modify. + /// @param values The set of new values for the preference. Passing {@code null} + /// for this argument is equivalent to calling {@link #remove(String)} with + /// this key. + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor putStringList(String key, List values) => + Editor._(_target.method('putStringSet', arguments: [key, values])); + + /// + /// Set an int value in the preferences editor, to be written back once + /// {@link #commit} or {@link #apply} are called. + /// + /// @param key The name of the preference to modify. + /// @param value The new value for the preference. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor putInt(String key, int value) => + Editor._(_target.method('putLong', arguments: [key, value])); + + /// + /// Set a float value in the preferences editor, to be written back once + /// {@link #commit} or {@link #apply} are called. + /// + /// @param key The name of the preference to modify. + /// @param value The new value for the preference. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor putFloat(String key, double value) => + Editor._(_target.method('putFloat', arguments: [key, value])); + + /// + /// Set a boolean value in the preferences editor, to be written back + /// once {@link #commit} or {@link #apply} are called. + /// + /// @param key The name of the preference to modify. + /// @param value The new value for the preference. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor putBool(String key, {bool value}) => + Editor._(_target.method('putBool', arguments: [key, value])); + + /// + /// Mark in the editor that a preference value should be removed, which + /// will be done in the actual preferences once {@link #commit} is + /// called. + /// + /// @param key The name of the preference to remove. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor remove(String key) => + Editor._(_target.method('remove', arguments: [key])); + + /// + /// Mark in the editor to remove all values from the + /// preferences. Once commit is called, the only remaining preferences + /// will be any that you have defined in this editor. + /// + /// @return Returns a reference to the same Editor object, so you can + /// chain put calls together. + /// + Editor clear() => Editor._(_target.method('clear')); + + /// + /// Commit your preferences changes back from this Editor to the + /// {@link SharedPreferences} object it is editing. This atomically + /// performs the requested modifications, replacing whatever is currently + /// in the SharedPreferences. + /// + ///

Note that when two editors are modifying preferences at the same + /// time, the last one to call commit wins. + /// + ///

If you don't care about the return value and you're + /// using this from your application's main thread, consider + /// using {@link #apply} instead. + /// + /// @return Returns true if the new values were successfully written + /// to persistent storage. + /// + Future commit() => _target.method('commit').invoke(); + + /// + /// Commit your preferences changes back from this Editor to the + /// {@link SharedPreferences} object it is editing. This atomically + /// performs the requested modifications, replacing whatever is currently + /// in the SharedPreferences. + /// + Future apply() => _target.method('apply').invoke(); +} + +class SharedPreferences implements NativeRuntimeClass { + SharedPreferences(this._target); + + final NativeTarget _target; + + static Future keep(NativeTarget target) async { + final success = await target.keep(); + if (!success) return null; + + return SharedPreferences(target); + } + + @override + Future dispose() => _target.dispose(); + + /// + /// Retrieve all values from the preferences. + /// + ///

Note that you must not modify the collection returned + /// by this method, or alter any of its contents. The consistency of your + /// stored data is not guaranteed if you do. + /// + /// @return Returns a map containing a list of pairs key/value representing + /// the preferences. + /// + /// @throws NullPointerException + /// + Future> get all => + _target.method('getAll').invoke>(); + + /// + /// Retrieve a String value from the preferences. + /// + /// @param key The name of the preference to retrieve. + /// @param defValue Value to return if this preference does not exist. + /// + /// @return Returns the preference value if it exists, or defValue. Throws + /// ClassCastException if there is a preference with this name that is not + /// a String. + /// + /// @throws ClassCastException + /// + Future string(String key, String defValue) => + _target.method('getString', arguments: [key, defValue]).invoke(); + + /// + /// Retrieve a set of String values from the preferences. + /// + ///

Note that you must not modify the set instance returned + /// by this call. The consistency of the stored data is not guaranteed + /// if you do, nor is your ability to modify the instance at all. + /// + /// @param key The name of the preference to retrieve. + /// @param defValues Values to return if this preference does not exist. + /// + /// @return Returns the preference values if they exist, or defValues. + /// Throws ClassCastException if there is a preference with this name + /// that is not a Set. + /// + /// @throws ClassCastException + /// + Future> stringList(String key, List defValues) => + _target.method('getStringSet', + arguments: [key, defValues]).invoke>(); + + /// + /// Retrieve an int value from the preferences. + /// + /// @param key The name of the preference to retrieve. + /// @param defValue Value to return if this preference does not exist. + /// + /// @return Returns the preference value if it exists, or defValue. Throws + /// ClassCastException if there is a preference with this name that is not + /// an int. + /// + /// @throws ClassCastException + /// + Future getInt(String key, int defValue) => + _target.method('getLong', arguments: [key, defValue]).invoke(); + + /// + /// Retrieve a float value from the preferences. + /// + /// @param key The name of the preference to retrieve. + /// @param defValue Value to return if this preference does not exist. + /// + /// @return Returns the preference value if it exists, or defValue. Throws + /// ClassCastException if there is a preference with this name that is not + /// a float. + /// + /// @throws ClassCastException + /// + Future getFloat(String key, double defValue) => + _target.method('getFloat', arguments: [key, defValue]).invoke(); + + /// + /// Retrieve a boolean value from the preferences. + /// + /// @param key The name of the preference to retrieve. + /// @param defValue Value to return if this preference does not exist. + /// + /// @return Returns the preference value if it exists, or defValue. Throws + /// ClassCastException if there is a preference with this name that is not + /// a boolean. + /// + /// @throws ClassCastException + /// + Future getBool(String key, {bool defValue}) => + _target.method('getBoolean', arguments: [key, defValue]).invoke(); + + /// + /// Checks whether the preferences contains a preference. + /// + /// @param key The name of the preference to check. + /// @return Returns true if the preference exists in the preferences, + /// otherwise false. + /// + Future contains(String key) => + _target.method('contains', arguments: [key]).invoke(); + + /// + /// Create a new Editor for these preferences, through which you can make + /// modifications to the data in the preferences and atomically commit those + /// changes back to the SharedPreferences object. + /// + ///

Note that you must call {@link Editor#commit} to have any + /// changes you perform in the Editor actually show up in the + /// SharedPreferences. + /// + /// @return Returns a new instance of the {@link Editor} interface, allowing + /// you to modify the values in this SharedPreferences object. + /// + Editor get edit => Editor._(_target.method('edit')); +} diff --git a/lib/src/ios/application.dart b/lib/src/ios/application.dart new file mode 100644 index 0000000..e1e2d5a --- /dev/null +++ b/lib/src/ios/application.dart @@ -0,0 +1,58 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class Application { + Application(this._target); + + factory Application.application() => + Application(applicationClass.method(_methodNameForSharedApplication)); + + static final applicationClass = + NativeRuntime().classNamed(_classNameForApplication); + + static const _methodNameForSharedApplication = 'sharedApplication'; + static const _classNameForApplication = 'UIApplication'; + + final NativeTarget _target; + + Future get networkActivityIndicatorVisible => + _target.property('networkActivityIndicatorVisible').get(); + + Future setNetworkActivityIndicatorVisible({@required bool visible}) => + _target.property('networkActivityIndicatorVisible').set(visible); + + Future get idleTimerDisabled => + _target.property('idleTimerDisabled').get(); + + Future setIdleTimerDisabled({@required bool disabled}) => + _target.property('idleTimerDisabled').set(disabled); + + Future get statusBarStyle => + _target.property('statusBarStyle').get(); + + Future get statusBarHidden => + _target.property('statusBarHidden').get(); + + Future get statusBarOrientation => + _target.property('statusBarOrientation').get(); + + Future get statusBarFrame => + _target.property('statusBarFrame').get(); + + Future get iconBadgeNumber => + _target.property('applicationIconBadgeNumber').get(); + + Future setIconBadgeNumber(int iconBadgeNumber) => + _target.property('applicationIconBadgeNumber').set(iconBadgeNumber); + + Future get supportsShakeToEdit => + _target.property('applicationSupportsShakeToEdit').get(); + + Future setSupportsShakeToEdit({bool supportsShakeToEdit}) => _target + .property('applicationSupportsShakeToEdit') + .set(supportsShakeToEdit); + + Future get state => _target.property('applicationState').get(); +} diff --git a/lib/src/ios/bundle.dart b/lib/src/ios/bundle.dart new file mode 100644 index 0000000..858236d --- /dev/null +++ b/lib/src/ios/bundle.dart @@ -0,0 +1,78 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class Bundle implements NativeRuntimeClass { + Bundle(this._target); + + factory Bundle.main() => Bundle(classTarget.property('mainBundle')); + + static Future from(String path, NativeTarget classTarget) async { + final target = classTarget.method('bundleWithPath:', arguments: [path]); + final success = await target.keep(); + if (!success) return null; + + return Bundle(target); + } + + @override + Future dispose() => _target.dispose(); + + static final classTarget = NativeRuntime().classNamed('NSBundle'); + + final NativeTarget _target; + + Future get bundlePath => _target.property('bundlePath').get(); + + Future get resourcePath => + _target.property('resourcePath').get(); + + Future get executablePath => + _target.property('executablePath').get(); + + Future get privateFrameworksPath => + _target.property('privateFrameworksPath').get(); + + Future get sharedFrameworksPath => + _target.property('sharedFrameworksPath').get(); + + Future get sharedSupportPath => + _target.property('sharedSupportPath').get(); + + Future get builtInPlugInsPath => + _target.property('builtInPlugInsPath').get(); + + Future get appStoreReceiptUri => + _target.property('appStoreReceiptURL').get(); + + Future get sharedSupportUri => + _target.property('sharedSupportURL').get(); + + Future get bundleIdentifier => + _target.property('bundleIdentifier').get(); + + Future get info => _target.property('infoDictionary').get(); + + Future get localizedInfo => + _target.property('localizedInfoDictionary').get(); + + Future get executableArchitectures => + _target.property('executableArchitectures').get(); + + Future pathForResource(String name, String type, String directory, + String localizationName) => + _target.method('pathForResource:ofType:inDirectory:forLocalization:', + arguments: [ + name, + type, + directory, + localizationName + ]).invoke(); + + Future> pathsForResourcesOfType( + String type, String directory, String localizationName) => + _target.method('pathsForResourcesOfType:inDirectory:forLocalization:', + arguments: [ + type, + directory, + localizationName + ]).invoke>(); +} diff --git a/lib/src/ios/device.dart b/lib/src/ios/device.dart new file mode 100644 index 0000000..4237483 --- /dev/null +++ b/lib/src/ios/device.dart @@ -0,0 +1,41 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +final _deviceClass = NativeRuntime().classNamed('UIDevice'); + +class Device { + Device(this._target); + + factory Device.current() => Device(_deviceClass.property('currentDevice')); + + final NativeTarget _target; + + Future get name => _target.property('name').get(); + Future get model => _target.property('model').get(); + Future get localizedModel => + _target.property('localizedModel').get(); + Future get systemName => _target.property('systemName').get(); + Future get systemVersion => + _target.property('systemVersion').get(); + Future get orientation => _target.property('orientation').get(); + Future get identifierForVendor => _target + .property('identifierForVendor') + .property('UUIDString') + .get(); + + Future get batteryMonitoringEnabled => + _target.property('batteryMonitoringEnabled').get(); + Future get batteryState => _target.property('batteryState').get(); + Future get batteryLevel => + _target.property('batteryLevel').get(); + + Future get proximityMonitoringEnabled => + _target.property('proximityMonitoringEnabled').get(); + Future get proximityState => + _target.property('proximityState').get(); + + Future get multitaskingSupported => + _target.property('multitaskingSupported').get(); + + Future get userInterfaceIdiom => + _target.property('userInterfaceIdiom').get(); +} diff --git a/lib/src/ios/process.dart b/lib/src/ios/process.dart new file mode 100644 index 0000000..d1b2060 --- /dev/null +++ b/lib/src/ios/process.dart @@ -0,0 +1,44 @@ +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class Process { + Process(this._target); + + factory Process.system() => + Process(classTarget.property(_propertyNameForProcessInfo)); + + static final classTarget = + NativeRuntime().classNamed(_classNameForProcessInfo); + + static const _classNameForProcessInfo = 'NSProcessInfo'; + static const _propertyNameForProcessInfo = 'processInfo'; + + final NativeTarget _target; + + Future get environment => _target.property('environment').get(); + Future get arguments => _target.property('arguments').get(); + + Future get hostName => _target.property('hostName').get(); + + Future get name => _target.property('processName').get(); + + Future get globallyUnique => + _target.property('globallyUniqueString').get(); + + Future get operatingSystemVersion => + _target.property('operatingSystemVersionString').get(); + + Future get processIdentifier => + _target.property('processIdentifier').get(); + + Future get processorCount => + _target.property('processorCount').get(); + + Future get physicalMemory => + _target.property('physicalMemory').get(); + + Future get systemUptime => + _target.property('systemUptime').get(); + + Future get automaticTerminationSupportEnabled => + _target.property('automaticTerminationSupportEnabled').get(); +} diff --git a/lib/src/ios/screen.dart b/lib/src/ios/screen.dart new file mode 100644 index 0000000..1985551 --- /dev/null +++ b/lib/src/ios/screen.dart @@ -0,0 +1,48 @@ +import 'dart:ui'; + +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +final _screenClass = NativeRuntime().classNamed('UIScreen'); + +class Screen { + Screen(this._target); + + factory Screen.main() => Screen(_screenClass.property('mainScreen')); + + final NativeTarget _target; + + Future get bounds => _target.property('bounds').get(); + + Future get scale => _target.property('scale').get(); + + Future get availableModes => + _target.property('availableModes').get(); + + Future get preferredMode => _target.property('preferredMode').get(); + + Future get currentMode => _target.property('currentMode').get(); + + Future get overscanCompensation => + _target.property('overscanCompensation').get(); + + Future get overscanCompensationInsets => + _target.property('overscanCompensationInsets').get(); + + Future get captured => _target.property('captured').get(); + + Future get nativeBounds => _target.property('nativeBounds').get(); + Future get nativeScale => + _target.property('nativeScale').get(); + + Future get maximumFramesPerSecond => + _target.property('maximumFramesPerSecond').get(); + + Future get calibratedLatency => + _target.property('calibratedLatency').get(); + + Future get supportsFocus => + _target.property('supportsFocus').get(); + + Future get applicationFrame => + _target.property('applicationFrame').get(); +} diff --git a/lib/src/ios/user_defaults.dart b/lib/src/ios/user_defaults.dart new file mode 100644 index 0000000..828fbc1 --- /dev/null +++ b/lib/src/ios/user_defaults.dart @@ -0,0 +1,132 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; + +class UserDefaults implements NativeRuntimeClass { + UserDefaults(this._target); + + factory UserDefaults.standard() => + UserDefaults(classTarget.property('standardUserDefaults')); + + static Future named( + String suiteName, NativeTarget classTarget) async { + final target = classTarget + .method('alloc') + .method('initWithSuiteName:', arguments: [suiteName]); + final success = await target.keep(); + if (!success) return null; + + return UserDefaults(target); + } + + static final classTarget = NativeRuntime().classNamed('NSUserDefaults'); + + final NativeTarget _target; + + @override + Future dispose() => _target.dispose(); + + Future objectForKey(String key) => + _target.method('objectForKey:', arguments: [key]).invoke(); + + Future boolForKey(String key) => + _target.method('boolForKey:', arguments: [key]).invoke(); + + Future setBool({ + @required bool value, + @required String key, + }) => + _target.method('setBool:forKey:', arguments: [value, key]).invoke(); + + Future intForKey(String key) => + _target.method('integerForKey:', arguments: [key]).invoke(); + + Future setInt(int value, String key) => _target + .method('setInteger:forKey:', arguments: [value, key]).invoke(); + + Future doubleForKey(String key) => + _target.method('doubleForKey:', arguments: [key]).invoke(); + + Future setDouble(double value, String key) => _target + .method('setDouble:forKey:', arguments: [value, key]).invoke(); + + Future stringForKey(String key) => + _target.method('stringForKey:', arguments: [key]).invoke(); + + Future setString(String value, String key) => _target + .method('setObject:forKey:', arguments: [value, key]).invoke(); + + Future setObject(value, String key) => _target + .method('setObject:forKey:', arguments: [value, key]).invoke(); + + Future> mapForKey(String key) async => (await _target + .method('dictionaryForKey:', arguments: [key]).invoke()) + .cast(); + + Future listForKey(String key) => + _target.method('arrayForKey:', arguments: [key]).invoke(); + + Future> stringListForKey(String key) async => (await _target + .method('stringArrayForKey:', arguments: [key]).invoke()) + .cast(); + + Future setUri(Uri uri, String key) => + _target.method('setURL:forKey:', arguments: [uri, key]).invoke(); + + Future registerDefaults(Map map) => + _target.method('registerDefaults:', arguments: [map]).invoke(); + + Future addSuite(String name) => + _target.method('addSuiteNamed:', arguments: [name]).invoke(); + + Future removeSuite(String name) => + _target.method('removeSuiteNamed:', arguments: [name]).invoke(); + + Future> get representation async => + (await _target.method('dictionaryRepresentation').invoke()) + .cast(); + + Future> get volatileDomainNames async => + (await _target.method('volatileDomainNames').invoke()) + .cast(); + + Future> volatileDomainNamed(String name) async => + (await _target.method('volatileDomainForName:', + arguments: [name]).invoke()) + .cast(); + + Future setVolatileDomain(Map domain, String name) => + _target.method('setVolatileDomain:forName:', + arguments: [domain, name]).invoke(); + + Future removeVolatileDomain(String name) => _target + .method('removeVolatileDomainForName:', arguments: [name]).invoke(); + + Future> get persistentDomainNames async => + (await _target.method('persistentDomainNames').invoke()) + .cast(); + + Future> persistentDomainNamed(String name) async => + (await _target.method('persistentDomainForName:', + arguments: [name]).invoke()) + .cast(); + + Future setPersistentDomain( + Map domain, String name) async => + _target.method('setPersistentDomain:forName:', + arguments: [domain, name]).invoke(); + + Future removePersistentDomain(String name) => + _target.method('removePersistentDomainForName:', + arguments: [name]).invoke(); + + Future synchronize() => _target.method('synchronize').invoke(); + + Future objectIsForcedForKey(String key, {String domain}) { + if (domain == null || domain.isEmpty) { + return _target + .method('objectIsForcedForKey:', arguments: [key]).invoke(); + } + return _target.method('objectIsForcedForKey:inDomain:', + arguments: [key, domain]).invoke(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..f3e6587 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,55 @@ +name: flutter_native +description: A new Flutter package project. +version: 0.0.1 +homepage: https://github.com/Modool/flutter_native + +environment: + sdk: ">=2.2.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_native_runtime: ^0.0.1 + +dev_dependencies: + flutter_test: + sdk: flutter + mockito: any + collection: any + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/test/application_info_test.dart b/test/application_info_test.dart new file mode 100644 index 0000000..11fe94e --- /dev/null +++ b/test/application_info_test.dart @@ -0,0 +1,443 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final info = ApplicationInfo(target, target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoResult(String name, List arguments) => _when(name, arguments, null); + + void _whenNoArgs(String name, T result, {isMethod = true}) { + if (isMethod) { + _when(name, null, result); + } else { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.memberVariable(name))), + )).thenAnswer((_) async => result); + } + } + + void _whenNoAny(String name) => _when(name, null, null); + + test('global', () async { + expect(ApplicationInfo.from(target), isNotNull); + }); + + test('targets', () async { + expect(info.applicationInfo, isNotNull); + }); + + group('properties', () { + setUp(() { + _whenNoArgs('taskAffinity', 'ok', isMethod: false); + _whenNoArgs('permission', 'ok', isMethod: false); + _whenNoArgs('processName', 'ok', isMethod: false); + _whenNoArgs('className', 'ok', isMethod: false); + _whenNoArgs('descriptionRes', 1, isMethod: false); + _whenNoArgs('theme', 1, isMethod: false); + _whenNoArgs('manageSpaceActivityName', 'ok', isMethod: false); + _whenNoArgs('backupAgentName', 'ok', isMethod: false); + _whenNoArgs('fullBackupContent', 1, isMethod: false); + _whenNoArgs('uiOptions', 1, isMethod: false); + _whenNoArgs('privateFlags', 1, isMethod: false); + _whenNoArgs('requiresSmallestWidthDp', 1, isMethod: false); + _whenNoArgs('compatibleWidthLimitDp', 1, isMethod: false); + _whenNoArgs('largestWidthLimitDp', 1, isMethod: false); + _whenNoArgs('maxAspectRatio', 0.5, isMethod: false); + _whenNoArgs('volumeUuid', 'ok', isMethod: false); + _whenNoArgs('scanSourceDir', 'ok', isMethod: false); + _whenNoArgs('scanPublicSourceDir', 'ok', isMethod: false); + _whenNoArgs('sourceDir', 'ok', isMethod: false); + _whenNoArgs('publicSourceDir', 'ok', isMethod: false); + _whenNoArgs>('splitNames', ['ok'], isMethod: false); + _whenNoArgs>('splitSourceDirs', ['ok'], isMethod: false); + _whenNoArgs>('splitPublicSourceDirs', ['ok'], isMethod: false); + _whenNoArgs>('resourceDirs', ['ok'], isMethod: false); + _whenNoArgs('seInfo', 'ok', isMethod: false); + _whenNoArgs('seInfoUser', 'ok', isMethod: false); + _whenNoArgs>('sharedLibraryFiles', ['ok'], isMethod: false); + _whenNoArgs('dataDir', 'ok', isMethod: false); + _whenNoArgs('deviceProtectedDataDir', 'ok', isMethod: false); + _whenNoArgs('credentialProtectedDataDir', 'ok', isMethod: false); + _whenNoArgs('nativeLibraryDir', 'ok', isMethod: false); + _whenNoArgs('secondaryNativeLibraryDir', 'ok', isMethod: false); + _whenNoArgs('nativeLibraryRootDir', 'ok', isMethod: false); + _whenNoArgs('nativeLibraryRootRequiresIsa', true, isMethod: false); + _whenNoArgs('primaryCpuAbi', 'ok', isMethod: false); + _whenNoArgs('secondaryCpuAbi', 'ok', isMethod: false); + _whenNoArgs('uid', 1, isMethod: false); + _whenNoArgs('minSdkVersion', 1, isMethod: false); + _whenNoArgs('targetSdkVersion', 1, isMethod: false); + _whenNoArgs('longVersionCode', 1, isMethod: false); + _whenNoArgs('versionCode', 1, isMethod: false); + _whenNoArgs('compileSdkVersion', 1, isMethod: false); + _whenNoArgs('compileSdkVersionCodename', 'ok', isMethod: false); + _whenNoArgs('enabled', true, isMethod: false); + _whenNoArgs('enabledSetting', 1, isMethod: false); + _whenNoArgs('installLocation', 1, isMethod: false); + _whenNoArgs('networkSecurityConfigRes', 1, isMethod: false); + _whenNoArgs('targetSandboxVersion', 1, isMethod: false); + _whenNoArgs('appComponentFactory', 1, isMethod: false); + _whenNoArgs('category', 1, isMethod: false); + _whenNoArgs('classLoaderName', 'ok', isMethod: false); + _whenNoArgs>('splitClassLoaderNames', ['ok'], isMethod: false); + _when('isValidHiddenApiEnforcementPolicy', [1], true); + _whenNoArgs('mHiddenApiPolicy', 1, isMethod: false); + _whenNoArgs('hasRtlSupport', true); + _whenNoArgs('hasCode', true); + _whenNoAny('disableCompatibilityMode'); + _whenNoArgs('usesCompatibilityMode', true); + _whenNoResult('initForUser', [1]); + _whenNoArgs('isPackageWhitelistedForHiddenApis', true); + _whenNoArgs('isAllowedToUseHiddenApis', true); + _whenNoArgs('getHiddenApiEnforcementPolicy', 1); + _whenNoResult('setHiddenApiEnforcementPolicy', [1]); + _whenNoAny('maybeUpdateHiddenApiEnforcementPolicy'); + _whenNoResult('setVersionCode', [1]); + _whenNoArgs('isDefaultToDeviceProtectedStorage', true); + _whenNoArgs('isDirectBootAware', true); + _whenNoArgs('isEncryptionAware', true); + _whenNoArgs('isExternal', true); + _whenNoArgs('isExternalAsec', true); + _whenNoArgs('isForwardLocked', true); + _whenNoArgs('isInstantApp', true); + _whenNoArgs('isInternal', true); + _whenNoArgs('isOem', true); + _whenNoArgs('isPartiallyDirectBootAware', true); + _whenNoArgs('isSignedWithPlatformKey', true); + _whenNoArgs('isPrivilegedApp', true); + _whenNoArgs('isRequiredForSystemUser', true); + _whenNoArgs('isStaticSharedLibrary', true); + _whenNoArgs('isSystemApp', true); + _whenNoArgs('isUpdatedSystemApp', true); + _whenNoArgs('isVendor', true); + _whenNoArgs('isProduct', true); + _whenNoArgs('isVirtualPreload', true); + _whenNoArgs('requestsIsolatedSplitLoading', true); + _whenNoResult('setCodePath', ['1']); + _whenNoResult('setBaseCodePath', ['1']); + _whenNoResult('setSplitCodePaths', [ + ['1'] + ]); + _whenNoResult('setResourcePath', ['1']); + _whenNoResult('setBaseResourcePath', ['1']); + _whenNoResult('setSplitResourcePaths', [ + ['1'] + ]); + _whenNoArgs('getCodePath', '1'); + _whenNoArgs('getBaseCodePath', '1'); + _whenNoArgs>('getSplitCodePaths', ['1']); + _whenNoArgs('getResourcePath', '1'); + _whenNoArgs('getBaseResourcePath', '1'); + _whenNoArgs>('getSplitResourcePaths', ['1']); + }); + + test('get taskAffinity', () async { + expect(await info.taskAffinity, 'ok'); + }); + test('get permission', () async { + expect(await info.permission, 'ok'); + }); + test('get processName', () async { + expect(await info.processName, 'ok'); + }); + test('get className', () async { + expect(await info.className, 'ok'); + }); + test('get descriptionRes', () async { + expect(await info.descriptionRes, 1); + }); + test('get theme', () async { + expect(await info.theme, 1); + }); + test('get manageSpaceActivityName', () async { + expect(await info.manageSpaceActivityName, 'ok'); + }); + test('get backupAgentName', () async { + expect(await info.backupAgentName, 'ok'); + }); + test('get fullBackupContent', () async { + expect(await info.fullBackupContent, 1); + }); + test('get uiOptions', () async { + expect(await info.uiOptions, 1); + }); + test('get privateFlags', () async { + expect(await info.privateFlags, 1); + }); + test('get requiresSmallestWidthDp', () async { + expect(await info.requiresSmallestWidthDp, 1); + }); + test('get compatibleWidthLimitDp', () async { + expect(await info.compatibleWidthLimitDp, 1); + }); + test('get largestWidthLimitDp', () async { + expect(await info.largestWidthLimitDp, 1); + }); + test('get maxAspectRatio', () async { + expect(await info.maxAspectRatio, 0.5); + }); + test('get volumeUuid', () async { + expect(await info.volumeUuid, 'ok'); + }); + test('get scanSourceDir', () async { + expect(await info.scanSourceDir, 'ok'); + }); + test('get scanPublicSourceDir', () async { + expect(await info.scanPublicSourceDir, 'ok'); + }); + test('get sourceDir', () async { + expect(await info.sourceDir, 'ok'); + }); + test('get publicSourceDir', () async { + expect(await info.publicSourceDir, 'ok'); + }); + test('get splitNames', () async { + expect(await info.splitNames, ['ok']); + }); + test('get splitSourceDirs', () async { + expect(await info.splitSourceDirs, ['ok']); + }); + test('get splitPublicSourceDirs', () async { + expect(await info.splitPublicSourceDirs, ['ok']); + }); + test('get resourceDirs', () async { + expect(await info.resourceDirs, ['ok']); + }); + test('get seInfo', () async { + expect(await info.seInfo, 'ok'); + }); + test('get seInfoUser', () async { + expect(await info.seInfoUser, 'ok'); + }); + test('get sharedLibraryFiles', () async { + expect(await info.sharedLibraryFiles, ['ok']); + }); + test('get dataDir', () async { + expect(await info.dataDir, 'ok'); + }); + test('get deviceProtectedDataDir', () async { + expect(await info.deviceProtectedDataDir, 'ok'); + }); + test('get credentialProtectedDataDir', () async { + expect(await info.credentialProtectedDataDir, 'ok'); + }); + test('get nativeLibraryDir', () async { + expect(await info.nativeLibraryDir, 'ok'); + }); + test('get secondaryNativeLibraryDir', () async { + expect(await info.secondaryNativeLibraryDir, 'ok'); + }); + test('get nativeLibraryRootDir', () async { + expect(await info.nativeLibraryRootDir, 'ok'); + }); + test('get nativeLibraryRootRequiresIsa', () async { + expect(await info.nativeLibraryRootRequiresIsa, true); + }); + test('get primaryCpuAbi', () async { + expect(await info.primaryCpuAbi, 'ok'); + }); + test('get secondaryCpuAbi', () async { + expect(await info.secondaryCpuAbi, 'ok'); + }); + test('get uid', () async { + expect(await info.uid, 1); + }); + test('get minSdkVersion', () async { + expect(await info.minSdkVersion, 1); + }); + test('get targetSdkVersion', () async { + expect(await info.targetSdkVersion, 1); + }); + test('get longVersionCode', () async { + expect(await info.longVersionCode, 1); + }); + test('get versionCode', () async { + expect(await info.versionCode, 1); + }); + test('get compileSdkVersion', () async { + expect(await info.compileSdkVersion, 1); + }); + test('get compileSdkVersionCodename', () async { + expect(await info.compileSdkVersionCodename, 'ok'); + }); + test('get enabled', () async { + expect(await info.enabled, true); + }); + test('get enabledSetting', () async { + expect(await info.enabledSetting, 1); + }); + test('get installLocation', () async { + expect(await info.installLocation, 1); + }); + test('get networkSecurityConfigRes', () async { + expect(await info.networkSecurityConfigRes, 1); + }); + test('get targetSandboxVersion', () async { + expect(await info.targetSandboxVersion, 1); + }); + test('get appComponentFactory', () async { + expect(await info.appComponentFactory, 1); + }); + test('get category', () async { + expect(await info.category, 1); + }); + test('get classLoaderName', () async { + expect(await info.classLoaderName, 'ok'); + }); + test('get splitClassLoaderNames', () async { + expect(await info.splitClassLoaderNames, ['ok']); + }); + test('get isValidHiddenApiEnforcementPolicy', () async { + expect(await info.isValidHiddenApiEnforcementPolicy(1), true); + }); + test('get mHiddenApiPolicy', () async { + expect(await info.mHiddenApiPolicy, 1); + }); + test('get hasRtlSupport', () async { + expect(await info.hasRtlSupport, true); + }); + test('get hasCode', () async { + expect(await info.hasCode, true); + }); + test('disableCompatibilityMode', () async { + await info.disableCompatibilityMode(); + }); + test('get usesCompatibilityMode', () async { + expect(await info.usesCompatibilityMode, true); + }); + test('initForUser', () async { + await info.initForUser(1); + }); + test('get packageWhitelistedForHiddenApis', () async { + expect(await info.packageWhitelistedForHiddenApis, true); + }); + test('get allowedToUseHiddenApis', () async { + expect(await info.allowedToUseHiddenApis, true); + }); + test('get hiddenApiEnforcementPolicy', () async { + expect(await info.hiddenApiEnforcementPolicy, 1); + }); + test('setHiddenApiEnforcementPolicy', () async { + await info.setHiddenApiEnforcementPolicy(1); + }); + test('maybeUpdateHiddenApiEnforcementPolicy', () async { + await info.maybeUpdateHiddenApiEnforcementPolicy(); + }); + test('setVersionCode', () async { + await info.setVersionCode(1); + }); + test('get isDefaultToDeviceProtectedStorage', () async { + expect(await info.isDefaultToDeviceProtectedStorage, true); + }); + test('get isDirectBootAware', () async { + expect(await info.isDirectBootAware, true); + }); + test('get isEncryptionAware', () async { + expect(await info.isEncryptionAware, true); + }); + test('get isExternal', () async { + expect(await info.isExternal, true); + }); + test('get isExternalAsec', () async { + expect(await info.isExternalAsec, true); + }); + test('get isForwardLocked', () async { + expect(await info.isForwardLocked, true); + }); + test('get isInstantApp', () async { + expect(await info.isInstantApp, true); + }); + test('get isInternal', () async { + expect(await info.isInternal, true); + }); + test('get isOem', () async { + expect(await info.isOem, true); + }); + test('get isPartiallyDirectBootAware', () async { + expect(await info.isPartiallyDirectBootAware, true); + }); + test('get isSignedWithPlatformKey', () async { + expect(await info.isSignedWithPlatformKey, true); + }); + test('get isPrivilegedApp', () async { + expect(await info.isPrivilegedApp, true); + }); + test('get isRequiredForSystemUser', () async { + expect(await info.isRequiredForSystemUser, true); + }); + test('get isStaticSharedLibrary', () async { + expect(await info.isStaticSharedLibrary, true); + }); + test('get isSystemApp', () async { + expect(await info.isSystemApp, true); + }); + test('get isUpdatedSystemApp', () async { + expect(await info.isUpdatedSystemApp, true); + }); + test('get isVendor', () async { + expect(await info.isVendor, true); + }); + test('get isProduct', () async { + expect(await info.isProduct, true); + }); + test('get isVirtualPreload', () async { + expect(await info.isVirtualPreload, true); + }); + test('get requestsIsolatedSplitLoading', () async { + expect(await info.requestsIsolatedSplitLoading(), true); + }); + + test('setCodePath', () async { + await info.setCodePath('1'); + }); + test('setBaseCodePath', () async { + await info.setBaseCodePath('1'); + }); + test('setSplitCodePaths', () async { + await info.setSplitCodePaths(['1']); + }); + test('setResourcePath', () async { + await info.setResourcePath('1'); + }); + test('setBaseResourcePath', () async { + await info.setBaseResourcePath('1'); + }); + test('setSplitResourcePaths', () async { + await info.setSplitResourcePaths(['1']); + }); + test('get codePath', () async { + expect(await info.codePath, '1'); + }); + test('get baseCodePath', () async { + expect(await info.baseCodePath, '1'); + }); + test('get splitCodePaths', () async { + expect(await info.splitCodePaths, ['1']); + }); + test('get resourcePath', () async { + expect(await info.resourcePath, '1'); + }); + test('get baseResourcePath', () async { + expect(await info.baseResourcePath, '1'); + }); + test('get splitResourcePaths', () async { + expect(await info.splitResourcePaths, ['1']); + }); + }); +} diff --git a/test/application_test.dart b/test/application_test.dart new file mode 100644 index 0000000..a8ced93 --- /dev/null +++ b/test/application_test.dart @@ -0,0 +1,80 @@ +import 'dart:ui'; + +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final application = Application(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property(name))), + )).thenAnswer((_) async => result); + } + + void _whenNoResult(String name, List arguments) => _when(name, arguments, null); + + void _whenNoArgs(String name, T result) => _when(name, null, result); + + test('global', () async { + expect(Application.application(), isNotNull); + }); + + test('networkActivityIndicatorVisible', () async { + _whenNoArgs('networkActivityIndicatorVisible', true); + expect(await application.networkActivityIndicatorVisible, true); + + _whenNoResult('networkActivityIndicatorVisible', [true]); + await application.setNetworkActivityIndicatorVisible(visible: true); + }); + + test('idleTimerDisabled', () async { + _whenNoArgs('idleTimerDisabled', true); + expect(await application.idleTimerDisabled, true); + + _whenNoResult('idleTimerDisabled', [true]); + await application.setIdleTimerDisabled(disabled: true); + }); + + test('status bar', () async { + _whenNoArgs('statusBarStyle', 1); + _whenNoArgs('statusBarHidden', true); + _whenNoArgs('statusBarOrientation', 1); + _whenNoArgs('statusBarFrame', const Rect.fromLTRB(1, 1, 1, 1)); + + expect(await application.statusBarStyle, 1); + expect(await application.statusBarHidden, true); + expect(await application.statusBarOrientation, 1); + expect(await application.statusBarFrame, const Rect.fromLTRB(1, 1, 1, 1)); + }); + + test('iconBadgeNumber', () async { + _whenNoArgs('applicationIconBadgeNumber', 1); + expect(await application.iconBadgeNumber, 1); + + _whenNoResult('applicationIconBadgeNumber', [1]); + await application.setIconBadgeNumber(1); + }); + + test('supportsShakeToEdit', () async { + _whenNoArgs('applicationSupportsShakeToEdit', true); + expect(await application.supportsShakeToEdit, true); + + _whenNoResult('applicationSupportsShakeToEdit', [true]); + await application.setSupportsShakeToEdit(supportsShakeToEdit: true); + }); + + test('state', () async { + _whenNoArgs('applicationState', true); + expect(await application.state, true); + }); +} diff --git a/test/asset_manager_test.dart b/test/asset_manager_test.dart new file mode 100644 index 0000000..88f1f69 --- /dev/null +++ b/test/asset_manager_test.dart @@ -0,0 +1,44 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final assetManager = AssetManager(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoAny(String name) => _when(name, null, null); + + test('global', () async { + expect(AssetManager.classTarget.isSameAs(runtime.classNamed('android.content.res.AssetManager')), true); + + expect(AssetManager.system(target), isNotNull); + expect(AssetManager.from(target), isNotNull); + }); + + group('methods', () { + setUp(() { + _whenNoAny('ensureValidLocked'); + _whenNoAny('ensureOpenLocked'); + }); + + test('ensureValidLocked', () async { + await assetManager.ensureValidLocked(); + }); + test('ensureOpenLocked', () async { + await assetManager.ensureOpenLocked(); + }); + }); +} diff --git a/test/build_test.dart b/test/build_test.dart new file mode 100644 index 0000000..a312836 --- /dev/null +++ b/test/build_test.dart @@ -0,0 +1,232 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final build = Build(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenVariable(String name, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.memberVariable(name))), + )).thenAnswer((_) async => result); + } + + void _whenNoArgs(String name, T result) => _when(name, null, result); + + group('Build', () { + test('global', () async { + expect(Build.system(), isNotNull); + }); + + group('methods', () { + setUp(() { + _whenVariable('TAG', 'ok'); + _whenVariable('UNKNOWN', 'ok'); + _whenVariable('ID', 'ok'); + _whenVariable('DISPLAY', 'ok'); + _whenVariable('PRODUCT', 'ok'); + _whenVariable('DEVICE', 'ok'); + _whenVariable('BOARD', 'ok'); + _whenVariable('CPU_ABI', 'ok'); + _whenVariable('CPU_ABI2', 'ok'); + _whenVariable('MANUFACTURER', 'ok'); + _whenVariable('BRAND', 'ok'); + _whenVariable('MODEL', 'ok'); + _whenVariable('BOOTLOADER', 'ok'); + _whenVariable('RADIO', 'ok'); + _whenVariable('HARDWARE', 'ok'); + _whenVariable('IS_EMULATOR', true); + _whenNoArgs('getSerial', 'ok'); + _whenVariable>('SUPPORTED_ABIS', ['ok']); + _whenVariable>('SUPPORTED_32_BIT_ABIS', ['ok']); + _whenVariable>('SUPPORTED_64_BIT_ABIS', ['ok']); + _whenVariable('TYPE', 'ok'); + _whenVariable('TAGS', 'ok'); + _whenVariable('FINGERPRINT', 'ok'); + _whenVariable('IS_TREBLE_ENABLED', true); + _whenVariable('TIME', 1); + _whenVariable('USER', 'ok'); + _whenVariable('HOST', 'ok'); + _whenVariable('IS_DEBUGGABLE', true); + _whenVariable('IS_ENG', true); + _whenVariable('IS_USERDEBUG', true); + _whenVariable('IS_USER', true); + _whenVariable('IS_CONTAINER', true); + _whenVariable('PERMISSIONS_REVIEW_REQUIRED', true); + _whenNoArgs('getRadioVersion', 'ok'); + }); + + test('variables', () async { + expect(await build.tag, 'ok'); + expect(await build.unknown, 'ok'); + expect(await build.id, 'ok'); + expect(await build.display, 'ok'); + expect(await build.product, 'ok'); + expect(await build.device, 'ok'); + expect(await build.board, 'ok'); + expect(await build.cpuAbi, 'ok'); + expect(await build.cpuAbi2, 'ok'); + expect(await build.manufacturer, 'ok'); + expect(await build.brand, 'ok'); + expect(await build.model, 'ok'); + expect(await build.bootloader, 'ok'); + expect(await build.radio, 'ok'); + expect(await build.hardware, 'ok'); + expect(await build.isEmulator, true); + expect(await build.serial, 'ok'); + expect(await build.supportedAbis, ['ok']); + expect(await build.supported32BitAbis, ['ok']); + expect(await build.supported64BitAbis, ['ok']); + expect(await build.type, 'ok'); + expect(await build.tags, 'ok'); + expect(await build.fingerprint, 'ok'); + expect(await build.isTrebleEnabled, true); + expect(await build.time, 1); + expect(await build.user, 'ok'); + expect(await build.host, 'ok'); + expect(await build.isDebuggable, true); + expect(await build.isEnglish, true); + expect(await build.isUserDebug, true); + expect(await build.isUser, true); + expect(await build.isContainer, true); + expect(await build.isPermissionReviewRequired, true); + expect(await build.radioVersion, 'ok'); + }); + }); + + group('Version', () { + test('global', () async { + expect(Version.system(), isNotNull); + }); + + group('methods', () { + final version = Version(target); + setUp(() { + _whenVariable('INCREMENTAL', 'ok'); + _whenVariable('RELEASE', 'ok'); + _whenVariable('BASE_OS', 'ok'); + _whenVariable('SECURITY_PATCH', 'ok'); + _whenVariable('SDK', 'ok'); + + _whenVariable('SDK_INT', 1); + _whenVariable('FIRST_SDK_INT', 1); + _whenVariable('PREVIEW_SDK_INT', 1); + + _whenVariable('CODENAME', 'ok'); + + _whenVariable>('ALL_CODENAMES', ['ok']); + _whenVariable>('ACTIVE_CODENAMES', ['ok']); + + _whenVariable('MIN_SUPPORTED_TARGET_SDK_INT', 1); + }); + + test('variables', () async { + expect(await version.incremental, 'ok'); + expect(await version.release, 'ok'); + expect(await version.baseOperatingSystem, 'ok'); + expect(await version.securityPatch, 'ok'); + expect(await version.sdk, 'ok'); + + expect(await version.sdkIntValue, 1); + expect(await version.firstSdkIntValue, 1); + expect(await version.previewSdk, 1); + + expect(await version.codeName, 'ok'); + + expect(await version.allCodeNames, ['ok']); + expect(await version.activeCodeNames, ['ok']); + + expect(await version.minSupportedTargetSdk, 1); + }); + }); + }); + + group('Version', () { + test('global', () async { + expect(VersionCodes.system(), isNotNull); + }); + + group('methods', () { + final versionCodes = VersionCodes(target); + setUp(() { + _whenVariable('CUR_DEVELOPMENT', 1); + _whenVariable('BASE', 1); + _whenVariable('BASE_1_1', 1); + _whenVariable('CUPCAKE', 1); + _whenVariable('DONUT', 1); + _whenVariable('ECLAIR', 1); + _whenVariable('ECLAIR_0_1', 1); + _whenVariable('ECLAIR_MR1', 1); + _whenVariable('FROYO', 1); + _whenVariable('GINGERBREAD', 1); + _whenVariable('HONEYCOMB', 1); + _whenVariable('HONEYCOMB_MR1', 1); + _whenVariable('HONEYCOMB_MR2', 1); + _whenVariable('ICE_CREAM_SANDWICH', 1); + _whenVariable('ICE_CREAM_SANDWICH_MR1', 1); + _whenVariable('JELLY_BEAN', 1); + _whenVariable('JELLY_BEAN_MR1', 1); + _whenVariable('JELLY_BEAN_MR2', 1); + _whenVariable('KITKAT', 1); + _whenVariable('KITKAT_WATCH', 1); + _whenVariable('L', 1); + _whenVariable('LOLLIPOP', 1); + _whenVariable('LOLLIPOP_MR1', 1); + _whenVariable('M', 1); + _whenVariable('N', 1); + _whenVariable('N_MR1', 1); + _whenVariable('O', 1); + _whenVariable('O_MR1', 1); + _whenVariable('P', 1); + }); + + test('variables', () async { + expect(await versionCodes.currentDevelopment, 1); + expect(await versionCodes.base, 1); + expect(await versionCodes.base1_1, 1); + expect(await versionCodes.cupcake, 1); + expect(await versionCodes.donut, 1); + expect(await versionCodes.eclair, 1); + expect(await versionCodes.eclair0_1, 1); + expect(await versionCodes.eclairMr1, 1); + expect(await versionCodes.froyo, 1); + expect(await versionCodes.gingerbread, 1); + expect(await versionCodes.homeyComb, 1); + expect(await versionCodes.homeyCombMr1, 1); + expect(await versionCodes.homeyCombMr2, 1); + expect(await versionCodes.iceCreamSandwich, 1); + expect(await versionCodes.iceCreamSandwichMr1, 1); + expect(await versionCodes.jellyBean, 1); + expect(await versionCodes.jellyBeanMr1, 1); + expect(await versionCodes.jellyBeanMr2, 1); + expect(await versionCodes.kitKat, 1); + expect(await versionCodes.kitKatWatch, 1); + expect(await versionCodes.l, 1); + expect(await versionCodes.lollipop, 1); + expect(await versionCodes.lollipopMr1, 1); + expect(await versionCodes.m, 1); + expect(await versionCodes.n, 1); + expect(await versionCodes.nMr1, 1); + expect(await versionCodes.o, 1); + expect(await versionCodes.oMr1, 1); + expect(await versionCodes.p, 1); + }); + }); + }); + }); +} diff --git a/test/bundle_test.dart b/test/bundle_test.dart new file mode 100644 index 0000000..2f1b862 --- /dev/null +++ b/test/bundle_test.dart @@ -0,0 +1,129 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +// ignore: avoid_implementing_value_types +class MockNativeTarget extends Mock implements NativeTarget {} + +// ignore: avoid_implementing_value_types +class MockNativeMethod extends Mock implements NativeMethod {} + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final bundle = Bundle(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenProperty(String name, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property(name))), + )).thenAnswer((_) async => result); + } + + test('global', () async { + expect(Bundle.main(), isNotNull); + + final mockTarget = MockNativeTarget(); + final mockMethod = MockNativeMethod(); + + when(mockTarget.method('bundleWithPath:', arguments: ['xxx/xx/xx'])).thenAnswer((_) => mockMethod); + + when(mockMethod.keep()).thenAnswer((_) async => true); + when(mockMethod.dispose()).thenAnswer((_) async => true); + + final bundle = await Bundle.from('xxx/xx/xx', mockTarget); + + expect(bundle, isInstanceOf()); + expect(await bundle.dispose(), true); + + when(mockMethod.keep()).thenAnswer((_) async => false); + expect(await Bundle.from('xxx/xx/xx', mockTarget), null); + }); + + test('bundlePath', () async { + _whenProperty('bundlePath', 'ok'); + expect(await bundle.bundlePath, 'ok'); + }); + + test('resourcePath', () async { + _whenProperty('resourcePath', 'ok'); + expect(await bundle.resourcePath, 'ok'); + }); + + test('executablePath', () async { + _whenProperty('executablePath', 'ok'); + expect(await bundle.executablePath, 'ok'); + }); + + test('privateFrameworksPath', () async { + _whenProperty('privateFrameworksPath', 'ok'); + expect(await bundle.privateFrameworksPath, 'ok'); + }); + + test('sharedFrameworksPath', () async { + _whenProperty('sharedFrameworksPath', 'ok'); + expect(await bundle.sharedFrameworksPath, 'ok'); + }); + + test('sharedSupportPath', () async { + _whenProperty('sharedSupportPath', 'ok'); + expect(await bundle.sharedSupportPath, 'ok'); + }); + + test('builtInPlugInsPath', () async { + _whenProperty('builtInPlugInsPath', 'ok'); + expect(await bundle.builtInPlugInsPath, 'ok'); + }); + + test('appStoreReceiptUri', () async { + _whenProperty('appStoreReceiptURL', 'ok'); + expect(await bundle.appStoreReceiptUri, 'ok'); + }); + + test('sharedSupportUri', () async { + _whenProperty('sharedSupportURL', 'ok'); + expect(await bundle.sharedSupportUri, 'ok'); + }); + + test('bundleIdentifier', () async { + _whenProperty('bundleIdentifier', 'ok'); + expect(await bundle.bundleIdentifier, 'ok'); + }); + + test('info', () async { + _whenProperty('infoDictionary', {'1': 'ok'}); + expect(await bundle.info, {'1': 'ok'}); + }); + + test('localizedInfo', () async { + _whenProperty('localizedInfoDictionary', {'1': 'ok'}); + expect(await bundle.localizedInfo, {'1': 'ok'}); + }); + + test('executableArchitectures', () async { + _whenProperty('executableArchitectures', ['1']); + expect(await bundle.executableArchitectures, ['1']); + }); + + test('pathForResource:ofType:inDirectory:forLocalization:', () async { + _when('pathForResource:ofType:inDirectory:forLocalization:', ['1', '2', '3', '4'], 'ok'); + expect(await bundle.pathForResource('1', '2', '3', '4'), 'ok'); + }); + + test('pathsForResourcesOfType:inDirectory:forLocalization:', () async { + _when>('pathsForResourcesOfType:inDirectory:forLocalization:', ['1', '2', '3'], ['ok']); + expect(await bundle.pathsForResourcesOfType('1', '2', '3'), ['ok']); + }); +} diff --git a/test/class_loader_test.dart b/test/class_loader_test.dart new file mode 100644 index 0000000..b6d46e9 --- /dev/null +++ b/test/class_loader_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final classLoader = ClassLoader(target, target); + + test('global', () async { + expect(ClassLoader.from(target), isNotNull); + }); + + group('methods', () { + setUp(() { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method('getResource', arguments: ['1']).method('toString'))), + )).thenAnswer((_) async => 'ok'); + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method('registerAsParallelCapable'))), + )).thenAnswer((_) async => true); + }); + + test('registerAsParallelCapable', () async { + expect(await classLoader.registerAsParallelCapable, true); + }); + + test('resource', () async { + expect(await classLoader.resource('1'), 'ok'); + }); + }); +} diff --git a/test/context_test.dart b/test/context_test.dart new file mode 100644 index 0000000..083e58e --- /dev/null +++ b/test/context_test.dart @@ -0,0 +1,319 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + test('global', () async { + expect(Context.global(), isNotNull); + }); + + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final context = Context(target); + + NativeTarget _target(String name, List arguments) => NativeTarget(name, NativeTargetType.method, target, runtime, arguments: arguments); + + NativeTarget _targetNoArgs(String name) => _target(name, null); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoResult(String name, List arguments) => _when(name, arguments, null); + void _whenNoArgs(String name, T result, {isMethod = true}) { + if (isMethod) { + _when(name, null, result); + } else { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.memberVariable(name))), + )).thenAnswer((_) async => result); + } + } + + void _whenNoAny(String name) => _when(name, null, null); + + test('targets', () async { + expect(context.assets, isInstanceOf()); + expect(context.resources, isInstanceOf()); + + expect(context.packageManager.isSameAs(_targetNoArgs('getPackageManager')), true); + expect(context.contentResolver.isSameAs(_targetNoArgs('getContentResolver')), true); + expect(context.mainLooper.isSameAs(_targetNoArgs('getMainLooper')), true); + expect(context.mainExecutor.isSameAs(_targetNoArgs('getMainExecutor')), true); + expect(context.applicationContext.isSameAs(_targetNoArgs('getApplicationContext')), true); + expect(context.drawable(1).isSameAs(_target('getDrawable', [1])), true); + expect(context.colorStateList(1).isSameAs(_target('getColorStateList', [1])), true); + expect(context.theme.isSameAs(_targetNoArgs('getTheme')), true); + expect(context.classLoader.isSameAs(_targetNoArgs('getClassLoader')), true); + expect(context.sharedPrefsFile('1').isSameAs(_target('getSharedPrefsFile', ['1'])), true); + expect(context.databasePath('1').isSameAs(_target('getDatabasePath', ['1'])), true); + expect(context.dataDir.isSameAs(_targetNoArgs('getDataDir')), true); + expect(context.filesDir.isSameAs(_targetNoArgs('getFilesDir')), true); + expect(context.noBackupFilesDir.isSameAs(_targetNoArgs('getNoBackupFilesDir')), true); + expect(context.externalFilesDir('1').isSameAs(_target('getExternalFilesDir', ['1'])), true); + expect(context.externalFilesDirs('1').isSameAs(_target('getExternalFilesDirs', ['1'])), true); + expect(context.obbDir.isSameAs(_targetNoArgs('getObbDir')), true); + expect(context.obbDirs.isSameAs(_targetNoArgs('getObbDirs')), true); + expect(context.cacheDir.isSameAs(_targetNoArgs('getCacheDir')), true); + expect(context.codeCacheDir.isSameAs(_targetNoArgs('getCodeCacheDir')), true); + expect(context.externalCacheDir.isSameAs(_targetNoArgs('getExternalCacheDir')), true); + expect(context.preloadsFileCache.isSameAs(_targetNoArgs('getPreloadsFileCache')), true); + expect(context.externalCacheDirs.isSameAs(_targetNoArgs('getExternalCacheDirs')), true); + expect(context.externalMediaDirs.isSameAs(_targetNoArgs('getExternalMediaDirs')), true); + expect(context.wallpaper.isSameAs(_targetNoArgs('getWallpaper')), true); + expect(context.peekWallpaper.isSameAs(_targetNoArgs('peekWallpaper')), true); + expect(context.systemService('1').isSameAs(_target('getSystemService', [1])), true); + expect(context.displayAdjustments(1).isSameAs(_target('getDisplayAdjustments', [1])), true); + expect(context.display.isSameAs(_targetNoArgs('getDisplay')), true); + expect(context.activityToken.isSameAs(_targetNoArgs('getActivityToken')), true); + }); + + group('methods', () { + final uri = Uri(host: 'www.bilibili.com'); + + setUp(() { + _when('getText', [1], 'ok'); + _when('getString', [1], 'ok'); + _when('getString', [1, 'format'], 'ok'); + _when('getColor', [1], 1); + _whenNoResult('setTheme', [1]); + _whenNoArgs('getThemeResId', 1); + _whenNoArgs('getPackageName', 'ok'); + _whenNoArgs('getBasePackageName', 'ok'); + _whenNoArgs('getOpPackageName', 'ok'); + _whenNoArgs('getPackageResourcePath', 'ok'); + _whenNoArgs('getPackageCodePath', 'ok'); + _when('deleteSharedPreferences', ['1'], true); + _whenNoAny('reloadSharedPreferences'); + _when('deleteFile', ['1'], true); + _whenNoArgs>('fileList', ['1']); + _when('deleteDatabase', ['1'], true); + _whenNoArgs>('databaseList', ['1']); + _whenNoArgs('getWallpaperDesiredMinimumWidth', 1); + _whenNoArgs('getWallpaperDesiredMinimumHeight', 1); + _whenNoArgs('clearWallpaper', null); + _whenNoArgs('canStartActivityForResult', true); + _when('checkPermission', ['1', 1, 1], 1); + _when('checkCallingPermission', ['1'], 1); + _when('checkCallingOrSelfPermission', ['1'], 1); + _when('checkSelfPermission', ['1'], 1); + _whenNoResult('enforcePermission', ['1', 1, 1, '1']); + _whenNoResult('enforceCallingPermission', ['1', '1']); + _whenNoResult('enforceCallingOrSelfPermission', ['1', '1']); + _whenNoResult('grantUriPermission', ['1', uri, 1]); + _whenNoResult('grantUriPermission', ['1', 1, uri]); + _when('checkCallingUriPermission', [uri, 1], 1); + _when('checkCallingOrSelfUriPermission', [uri, 1], 1); + _when('checkUriPermission', [uri, '1', '2', 1, 1, 1], 1); + _whenNoResult('enforceCallingUriPermission', [uri, 1, '1']); + _whenNoResult('enforceCallingOrSelfUriPermission', [uri, 1, '1']); + _whenNoResult('enforceUriPermission', [uri, '2', '3', 1, 1, 1, '1']); + _whenNoArgs('getUserId', 1); + _whenNoResult('updateDisplay', [1]); + _whenNoArgs('isRestricted', true); + _whenNoArgs('isDeviceProtectedStorage', true); + _whenNoArgs('isCredentialProtectedStorage', true); + _whenNoArgs('canLoadUnsafeResources', true); + _whenNoArgs('isAutofillCompatibilityEnabled', true); + _whenNoResult('setAutofillCompatibilityEnabled', [true]); + _whenNoAny('assertRuntimeOverlayThemable'); + }); + + test('get text', () async { + expect(await context.text(1), 'ok'); + }); + + test('get string', () async { + expect(await context.string(1), 'ok'); + }); + + test('get text with format', () async { + expect(await context.stringWithFromat(1, ['format']), 'ok'); + }); + + test('get color', () async { + expect(await context.color(1), 1); + }); + + test('set theme', () async { + await context.setTheme(1); + }); + + test('get theme by id', () async { + expect(await context.themeResId(), 1); + }); + + test('get package name', () async { + expect(await context.packageName, 'ok'); + }); + + test('get base package name', () async { + expect(await context.basePackageName, 'ok'); + }); + + test('get op package name', () async { + expect(await context.opPackageName, 'ok'); + }); + + test('get applicationInfo', () async { + expect(context.applicationInfo, isInstanceOf()); + }); + + test('get packageResourcePath', () async { + expect(await context.packageResourcePath, 'ok'); + }); + + test('get packageCodePath', () async { + expect(await context.packageCodePath, 'ok'); + }); + + test('get sharedPreferences', () async { + expect(context.sharedPreferences('1', 1), isInstanceOf()); + }); + + test('deleteSharedPreferences', () async { + expect(await context.deleteSharedPreferences('1'), true); + }); + + test('reloadSharedPreferences', () async { + await context.reloadSharedPreferences(); + }); + + test(' deleteFile 1', () async { + expect(await context.deleteFile('1'), true); + }); + + test('fileList', () async { + expect(await context.fileList, ['1']); + }); + + test('deleteDatabase', () async { + expect(await context.deleteDatabase('1'), true); + }); + + test('databaseList', () async { + expect(await context.databaseList, ['1']); + }); + + test('wallpaperDesiredMinimumWidth', () async { + expect(await context.wallpaperDesiredMinimumWidth, 1); + }); + + test('wallpaperDesiredMinimumHeight', () async { + expect(await context.wallpaperDesiredMinimumHeight, 1); + }); + + test('clearWallpaper', () async { + await context.clearWallpaper(); + }); + + test('canStartActivityForResult', () async { + expect(await context.canStartActivityForResult, true); + }); + + test('checkPermission', () async { + expect(await context.checkPermission('1', 1, 1), 1); + }); + + test('checkCallingPermission', () async { + expect(await context.checkCallingPermission('1'), 1); + }); + + test('checkCallingOrSelfPermission', () async { + expect(await context.checkCallingOrSelfPermission('1'), 1); + }); + + test('checkSelfPermission', () async { + expect(await context.checkSelfPermission('1'), 1); + }); + + test('enforcePermission', () async { + await context.enforcePermission('1', 1, 1, '1'); + }); + + test('enforceCallingPermission', () async { + await context.enforceCallingPermission('1', '1'); + }); + + test('enforceCallingOrSelfPermission', () async { + await context.enforceCallingOrSelfPermission('1', '1'); + }); + + test('grantUriPermission', () async { + await context.grantUriPermission('1', uri, 1); + }); + + test('revokeUriPermission', () async { + await context.revokeUriPermission('1', 1, uri: uri); + }); + + test('checkCallingUriPermission', () async { + expect(await context.checkCallingUriPermission(uri, 1), 1); + }); + + test('checkCallingOrSelfUriPermission', () async { + expect(await context.checkCallingOrSelfUriPermission(uri, 1), 1); + }); + + test('checkUriPermission', () async { + expect(await context.checkUriPermission(uri, 1, 1, 1, readPermission: '1', writePermission: '2'), 1); + }); + + test('enforceCallingUriPermission', () async { + await context.enforceCallingUriPermission(uri, 1, '1'); + }); + + test('enforceCallingOrSelfUriPermission', () async { + await context.enforceCallingOrSelfUriPermission(uri, 1, '1'); + }); + + test('enforceUriPermission', () async { + await context.enforceUriPermission(uri, 1, 1, 1, '1', readPermission: '2', writePermission: '3'); + }); + + test('updateDisplay', () async { + await context.updateDisplay(1); + }); + + test('userId', () async { + expect(await context.userId, 1); + }); + + test('restricted', () async { + expect(await context.restricted, true); + }); + + test('deviceProtectedStorage', () async { + expect(await context.deviceProtectedStorage, true); + }); + + test('credentialProtectedStorage', () async { + expect(await context.credentialProtectedStorage, true); + }); + + test('canLoadUnsafeResources', () async { + expect(await context.canLoadUnsafeResources, true); + }); + + test('autofillCompatibilityEnabled', () async { + expect(await context.autofillCompatibilityEnabled, true); + }); + + test('setAutofillCompatibilityEnabled', () async { + await context.setAutofillCompatibilityEnabled(autofillCompatEnabled: true); + }); + + test('assertRuntimeOverlayThemable', () async { + await context.assertRuntimeOverlayThemable(); + }); + }); +} diff --git a/test/device_test.dart b/test/device_test.dart new file mode 100644 index 0000000..8622294 --- /dev/null +++ b/test/device_test.dart @@ -0,0 +1,114 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final device = Device(target); + + void _whenProperty(String name, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property(name))), + )).thenAnswer((_) async => result); + } + + test('global', () async { + expect(Device.current(), isNotNull); + }); + + test('name', () async { + _whenProperty('name', 'ok'); + expect(await device.name, 'ok'); + }); + + test('model', () async { + _whenProperty('model', 'ok'); + expect(await device.model, 'ok'); + }); + + test('localizedModel', () async { + _whenProperty('localizedModel', 'ok'); + expect(await device.localizedModel, 'ok'); + }); + + test('systemName', () async { + _whenProperty('systemName', 'ok'); + expect(await device.systemName, 'ok'); + }); + + test('systemVersion', () async { + _whenProperty('systemVersion', 'ok'); + expect(await device.systemVersion, 'ok'); + }); + + test('orientation', () async { + _whenProperty('orientation', 1); + expect(await device.orientation, 1); + }); + + test('systemVersion', () async { + _whenProperty('systemVersion', 'ok'); + expect(await device.systemVersion, 'ok'); + }); + + test('systemVersion', () async { + _whenProperty('systemVersion', 'ok'); + expect(await device.systemVersion, 'ok'); + }); + + test('systemVersion', () async { + _whenProperty('systemVersion', 'ok'); + expect(await device.systemVersion, 'ok'); + }); + + test('identifierForVendor', () async { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property('identifierForVendor').property('UUIDString'))), + )).thenAnswer((_) async => 'ok'); + _whenProperty('identifierForVendor', 'ok'); + expect(await device.identifierForVendor, 'ok'); + }); + + test('batteryMonitoringEnabled', () async { + _whenProperty('batteryMonitoringEnabled', true); + expect(await device.batteryMonitoringEnabled, true); + }); + + test('batteryState', () async { + _whenProperty('batteryState', 1); + expect(await device.batteryState, 1); + }); + + test('batteryLevel', () async { + _whenProperty('batteryLevel', 0.5); + expect(await device.batteryLevel, 0.5); + }); + + test('proximityMonitoringEnabled', () async { + _whenProperty('proximityMonitoringEnabled', true); + expect(await device.proximityMonitoringEnabled, true); + }); + + test('proximityState', () async { + _whenProperty('proximityState', true); + expect(await device.proximityState, true); + }); + + test('multitaskingSupported', () async { + _whenProperty('multitaskingSupported', true); + expect(await device.multitaskingSupported, true); + }); + + test('userInterfaceIdiom', () async { + _whenProperty('userInterfaceIdiom', 1); + expect(await device.userInterfaceIdiom, 1); + }); +} diff --git a/test/matcher.dart b/test/matcher.dart new file mode 100644 index 0000000..941ed59 --- /dev/null +++ b/test/matcher.dart @@ -0,0 +1,37 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +class TargetMatcher extends Matcher { + TargetMatcher(this.target); + + final NativeTarget target; + + @override + Description describe(Description description) => description.add('$target'); + + @override + bool matches(item, Map matchState) { + if (item is Map) { + return _matches(item, target.toMap()); + } + return false; + } + + bool _matches(Map item1, Map item2) { + if (item1 == item2) return true; + + if (item1['n'] != item2['n']) return false; + if (item1['t'] != item2['t']) return false; + + final a1 = item1['a']; + final a2 = item2['a']; + + if (a1.toString() != a2.toString()) return false; + + return _matches(item1['p'], item2['p']); + } +} + +class MockChannel extends Mock implements MethodChannel {} diff --git a/test/process_test.dart b/test/process_test.dart new file mode 100644 index 0000000..96ddde2 --- /dev/null +++ b/test/process_test.dart @@ -0,0 +1,80 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final process = Process(target); + + void _whenProperty(String name, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property(name))), + )).thenAnswer((_) async => result); + } + + test('global', () async { + expect(Process.system(), isNotNull); + }); + + test('environment', () async { + _whenProperty('environment', {'1': 'ok'}); + expect(await process.environment, {'1': 'ok'}); + }); + + test('arguments', () async { + _whenProperty('arguments', ['1']); + expect(await process.arguments, ['1']); + }); + + test('hostName', () async { + _whenProperty('hostName', 'ok'); + expect(await process.hostName, 'ok'); + }); + + test('processName', () async { + _whenProperty('processName', 'ok'); + expect(await process.name, 'ok'); + }); + + test('globallyUnique', () async { + _whenProperty('globallyUniqueString', 'ok'); + expect(await process.globallyUnique, 'ok'); + }); + + test('operatingSystemVersion', () async { + _whenProperty('operatingSystemVersionString', 'ok'); + expect(await process.operatingSystemVersion, 'ok'); + }); + + test('processIdentifier', () async { + _whenProperty('processIdentifier', 1); + expect(await process.processIdentifier, 1); + }); + + test('processorCount', () async { + _whenProperty('processorCount', 1); + expect(await process.processorCount, 1); + }); + + test('physicalMemory', () async { + _whenProperty('physicalMemory', 1); + expect(await process.physicalMemory, 1); + }); + + test('systemUptime', () async { + _whenProperty('systemUptime', 0.5); + expect(await process.systemUptime, 0.5); + }); + + test('automaticTerminationSupportEnabled', () async { + _whenProperty('automaticTerminationSupportEnabled', true); + expect(await process.automaticTerminationSupportEnabled, true); + }); +} diff --git a/test/resources_imp_test.dart b/test/resources_imp_test.dart new file mode 100644 index 0000000..cacc694 --- /dev/null +++ b/test/resources_imp_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final resourcesImpl = ResourcesImpl(target, target); + + test('global', () async { + expect(ResourcesImpl.from(target), isNotNull); + }); + + group('methods', () { + setUp(() { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method('attrForQuantityCode', arguments: ['1']))), + )).thenAnswer((_) async => 1); + }); + + test('asset', () async { + expect(resourcesImpl.assets, isInstanceOf()); + }); + test('attrForQuantityCode', () async { + expect(await resourcesImpl.attrForQuantityCode('1'), 1); + }); + }); +} diff --git a/test/resources_test.dart b/test/resources_test.dart new file mode 100644 index 0000000..d9c94de --- /dev/null +++ b/test/resources_test.dart @@ -0,0 +1,146 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final resources = Resources(target, target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoResult(String name, List arguments) => _when(name, arguments, null); + + void _whenNoAny(String name) => _when(name, null, null); + + test('global', () async { + expect(Resources.system(), isNotNull); + expect(Resources.from(target), isNotNull); + }); + + test('targets', () async { + expect(resources.assetManager, isInstanceOf()); + expect(resources.impl, isInstanceOf()); + expect(resources.classLoader, isInstanceOf()); + }); + + group('methods', () { + setUp(() { + _when('selectDefaultTheme', [1, 2], 1); + _when('selectSystemTheme', [1, 2, 3, 4, 5, 6], 1); + _whenNoResult('preloadFonts', [1]); + _when('getQuantityText', [1, 2], 'ok'); + _when('getString', [1], 'ok'); + _when('getString', [1, '2'], 'ok'); + _when('getQuantityString', [1, 2, '3'], 'ok'); + _when('getQuantityString', [1, 2], 'ok'); + _when>('getStringArray', [1], ['ok']); + _when>('getIntArray', [1], [1]); + _when('getDimension', [1], 0.5); + _when('getDimensionPixelOffset', [1], 1); + _when('getDimensionPixelSize', [1], 1); + _when('getFraction', [1, 2, 3], 0.5); + _when('getColor', [1], 1); + _when('getBoolean', [1], true); + _when('getInteger', [1], 1); + _when('getIdentifier', ['1', '2', '3'], 1); + _when('resourceHasPackage', [1], true); + _when('getResourceName', [1], 'ok'); + _when('getResourcePackageName', [1], 'ok'); + _when('getResourceTypeName', [1], 'ok'); + _when('getResourceEntryName', [1], 'ok'); + _whenNoAny('flushLayoutCache'); + _whenNoAny('startPreloading'); + _whenNoAny('finishPreloading'); + }); + + test('selectDefaultTheme 1 2', () async { + expect(await resources.selectDefaultTheme(1, 2), 1); + }); + test('selectSystemTheme 1 2 3 4 5 6', () async { + expect(await resources.selectSystemTheme(1, 2, 3, 4, 5, 6), 1); + }); + test('preloadFonts 1', () async { + await resources.preloadFonts(1); + }); + test('quantityText 1 2', () async { + expect(await resources.quantityText(1, 2), 'ok'); + }); + test('string 1', () async { + expect(await resources.string(1), 'ok'); + }); + test('stringWithFromat 1 2', () async { + expect(await resources.stringWithFromat(1, ['2']), 'ok'); + }); + test('quantityStringWithFromat 1 2 3', () async { + expect(await resources.quantityStringWithFromat(1, 2, ['3']), 'ok'); + }); + test('getQuantityString 1 2', () async { + expect(await resources.quantityString(1, 2), 'ok'); + }); + test('stringArray 1', () async { + expect(await resources.stringArray(1), ['ok']); + }); + test('intArray 1', () async { + expect(await resources.intArray(1), [1]); + }); + test('dimension 1', () async { + expect(await resources.dimension(1), 0.5); + }); + test('dimensionPixelOffset 1', () async { + expect(await resources.dimensionPixelOffset(1), 1); + }); + test('dimensionPixelSize 1', () async { + expect(await resources.dimensionPixelSize(1), 1); + }); + test('fraction 1 2 3', () async { + expect(await resources.fraction(1, 2, 3), 0.5); + }); + test('color 1', () async { + expect(await resources.color(1), 1); + }); + test('boolean 1', () async { + expect(await resources.boolean(1), true); + }); + test('integer 1', () async { + expect(await resources.integer(1), 1); + }); + test('dentifier 1 2 3', () async { + expect(await resources.dentifier('1', '2', '3'), 1); + }); + test('resourceHasPackage 1', () async { + expect(await resources.resourceHasPackage(1), true); + }); + test('resourceName 1', () async { + expect(await resources.resourceName(1), 'ok'); + }); + test('resourcePackageName 1', () async { + expect(await resources.resourcePackageName(1), 'ok'); + }); + test('resourceTypeName 1', () async { + expect(await resources.resourceTypeName(1), 'ok'); + }); + test('resourceEntryName 1', () async { + expect(await resources.resourceEntryName(1), 'ok'); + }); + test('flushLayoutCache', () async { + await resources.flushLayoutCache(); + }); + test('startPreloading', () async { + await resources.startPreloading(); + }); + test('finishPreloading', () async { + await resources.finishPreloading(); + }); + }); +} diff --git a/test/screen_test.dart b/test/screen_test.dart new file mode 100644 index 0000000..a853f43 --- /dev/null +++ b/test/screen_test.dart @@ -0,0 +1,97 @@ +import 'dart:ui'; + +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final screen = Screen(target); + + void _whenProperty(String name, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.property(name))), + )).thenAnswer((_) async => result); + } + + test('global', () async { + expect(Screen.main(), isNotNull); + }); + + test('bounds', () async { + _whenProperty('bounds', const Rect.fromLTRB(1, 1, 1, 1)); + expect(await screen.bounds, const Rect.fromLTRB(1, 1, 1, 1)); + }); + + test('scale', () async { + _whenProperty('scale', 0.5); + expect(await screen.scale, 0.5); + }); + + test('availableModes', () async { + _whenProperty('availableModes', ['1']); + expect(await screen.availableModes, ['1']); + }); + + test('preferredMode', () async { + _whenProperty('preferredMode', 1); + expect(await screen.preferredMode, 1); + }); + + test('currentMode', () async { + _whenProperty('currentMode', 1); + expect(await screen.currentMode, 1); + }); + + test('overscanCompensation', () async { + _whenProperty('overscanCompensation', 1); + expect(await screen.overscanCompensation, 1); + }); + + test('overscanCompensationInsets', () async { + _whenProperty('overscanCompensationInsets', {'1': 'ok'}); + expect(await screen.overscanCompensationInsets, {'1': 'ok'}); + }); + + test('captured', () async { + _whenProperty('captured', true); + expect(await screen.captured, true); + }); + + test('nativeBounds', () async { + _whenProperty('nativeBounds', const Rect.fromLTRB(1, 1, 1, 1)); + expect(await screen.nativeBounds, const Rect.fromLTRB(1, 1, 1, 1)); + }); + + test('nativeScale', () async { + _whenProperty('nativeScale', 0.5); + expect(await screen.nativeScale, 0.5); + }); + + test('maximumFramesPerSecond', () async { + _whenProperty('maximumFramesPerSecond', 1); + expect(await screen.maximumFramesPerSecond, 1); + }); + + test('calibratedLatency', () async { + _whenProperty('calibratedLatency', 0.5); + expect(await screen.calibratedLatency, 0.5); + }); + + test('supportsFocus', () async { + _whenProperty('supportsFocus', true); + expect(await screen.supportsFocus, true); + }); + + test('applicationFrame', () async { + _whenProperty('applicationFrame', const Rect.fromLTRB(1, 1, 1, 1)); + expect(await screen.applicationFrame, const Rect.fromLTRB(1, 1, 1, 1)); + }); +} diff --git a/test/shared_preference_test.dart b/test/shared_preference_test.dart new file mode 100644 index 0000000..0e1f5c1 --- /dev/null +++ b/test/shared_preference_test.dart @@ -0,0 +1,184 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +// ignore: avoid_implementing_value_types +class MockNativeTarget extends Mock implements NativeTarget {} + +// ignore: avoid_implementing_value_types +class MockNativeMethod extends Mock implements NativeMethod {} + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final sharedPreferences = SharedPreferences(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoArgs(String name, T result, {isMethod = true}) { + if (isMethod) { + _when(name, null, result); + } else { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.memberVariable(name))), + )).thenAnswer((_) async => result); + } + } + + test('global', () async { + expect(AssetManager.system(target), isNotNull); + expect(AssetManager.from(target), isNotNull); + + final mockTarget = MockNativeTarget(); + + when(mockTarget.keep()).thenAnswer((_) async => true); + when(mockTarget.dispose()).thenAnswer((_) async => true); + + final defaults = await SharedPreferences.keep(mockTarget); + expect(defaults, isInstanceOf()); + expect(await defaults.dispose(), true); + + when(mockTarget.keep()).thenAnswer((_) async => false); + expect(await SharedPreferences.keep(mockTarget), null); + }); + + group('shared preference methods', () { + setUp(() { + _whenNoArgs>('getAll', {'1': 2}); + _when('getString', ['1', '2'], 'ok'); + _when>( + 'getStringSet', + [ + '1', + ['2'] + ], + ['ok'], + ); + _when('getLong', ['1', 2], 1); + _when('getFloat', ['1', 0.5], 0.5); + _when('getBoolean', ['1', true], true); + _when('contains', ['1'], true); + }); + + test('all', () async { + expect(await sharedPreferences.all, {'1': 2}); + }); + test('string', () async { + expect(await sharedPreferences.string('1', '2'), 'ok'); + }); + test('stringList', () async { + expect(await sharedPreferences.stringList('1', ['2']), ['ok']); + }); + test('getInt', () async { + expect(await sharedPreferences.getInt('1', 2), 1); + }); + test('getFloat', () async { + expect(await sharedPreferences.getFloat('1', 0.5), 0.5); + }); + test('getBool', () async { + expect(await sharedPreferences.getBool('1', defValue: true), true); + }); + test('contains', () async { + expect(await sharedPreferences.contains('1'), true); + }); + + test('contains', () async { + expect(sharedPreferences.edit, isInstanceOf()); + }); + }); + + group('editor methods', () { + final editor = sharedPreferences.edit; + + void _when(String name, List arguments) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher( + target.method('edit').method(name, arguments: arguments).method('commit'), + )), + )).thenAnswer((_) async => true); + } + + setUp(() { + _whenNoArgs('commit', true); + + _when('putString', ['1', '2']); + _when('putStringList', [ + '1', + ['2'] + ]); + _when('putInt', ['1', 2]); + _when('putFloat', ['1', 0.5]); + _when('putBool', ['1', true]); + _when('remove', ['1']); + + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher( + target.method('edit').method('commit'), + )), + )).thenAnswer((_) async => true); + + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher( + target.method('edit').method('apply'), + )), + )).thenAnswer((_) async => null); + }); + + test('putString', () async { + expect(editor.putString('1', '2'), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('putStringList', () async { + expect(editor.putStringList('1', ['2']), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('putInt', () async { + expect(editor.putInt('1', 2), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('putFloat', () async { + expect(editor.putFloat('1', 0.5), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('putBool', () async { + expect(editor.putBool('1', value: true), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('remove', () async { + expect(editor.remove('1'), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('clear', () async { + expect(editor.clear(), isInstanceOf()); + expect(await editor.commit(), true); + }); + + test('commit', () async { + expect(await editor.commit(), true); + }); + + test('apply', () async { + await editor.apply(); + }); + }); +} diff --git a/test/user_default_test.dart b/test/user_default_test.dart new file mode 100644 index 0000000..75553bc --- /dev/null +++ b/test/user_default_test.dart @@ -0,0 +1,218 @@ +import 'package:flutter_native/flutter_native.dart'; +import 'package:flutter_native_runtime/flutter_native_runtime.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +import 'matcher.dart'; + +// ignore: avoid_implementing_value_types +class MockNativeTarget extends Mock implements NativeTarget {} + +// ignore: avoid_implementing_value_types +class MockNativeMethod extends Mock implements NativeMethod {} + +// ignore: avoid_implementing_value_types +class MockNativeProperty extends Mock implements NativeProperty {} + +// ignore: avoid_implementing_value_types +class MockNativeMemberVariable extends Mock implements NativeMemberVariable {} + +void main() { + final channel = MockChannel(); + final runtime = TestNativeRuntime(channel); + + final target = runtime.instanceNamed('mock'); + final userDefaults = UserDefaults(target); + + void _when(String name, List arguments, T result) { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.method(name, arguments: arguments))), + )).thenAnswer((_) async => result); + } + + void _whenNoArgs(String name, T result, {isMethod = true}) { + if (isMethod) { + _when(name, null, result); + } else { + when(channel.invokeMethod( + 'invoke', + argThat(TargetMatcher(target.memberVariable(name))), + )).thenAnswer((_) async => result); + } + } + + void _whenNoResult(String name, List arguments) => _when(name, arguments, null); + + test('global', () async { + expect(UserDefaults.standard(), isInstanceOf()); + + final mockTarget = MockNativeTarget(); + final mockMethod = MockNativeMethod(); + + when(mockTarget.method('alloc')).thenAnswer((_) => mockMethod); + + when(mockMethod.method('initWithSuiteName:', arguments: ['test'])).thenAnswer((_) => mockMethod); + when(mockMethod.keep()).thenAnswer((_) async => true); + when(mockMethod.dispose()).thenAnswer((_) async => true); + + final defaults = await UserDefaults.named('test', mockTarget); + + expect(defaults, isInstanceOf()); + expect(await defaults.dispose(), true); + + when(mockMethod.keep()).thenAnswer((_) async => false); + expect(await UserDefaults.named('test', mockTarget), null); + }); + + test('boolForKey', () async { + _when('boolForKey:', ['1'], true); + expect(await userDefaults.boolForKey('1'), true); + }); + + test('objectForKey', () async { + _when('objectForKey:', ['1'], true); + expect(await userDefaults.objectForKey('1'), true); + }); + + test('setBool', () async { + _whenNoResult('setBool:forKey:', [true, '1']); + await userDefaults.setBool(value: true, key: '1'); + }); + + test('intForKey', () async { + _when('integerForKey:', ['1'], 1); + expect(await userDefaults.intForKey('1'), 1); + }); + + test('setInt', () async { + _whenNoResult('setInteger:forKey:', [1, '1']); + await userDefaults.setInt(1, '1'); + }); + + test('doubleForKey', () async { + _when('doubleForKey:', ['1'], 0.5); + expect(await userDefaults.doubleForKey('1'), 0.5); + }); + + test('setDouble', () async { + _whenNoResult('setDouble:forKey:', [0.5, '1']); + await userDefaults.setDouble(0.5, '1'); + }); + + test('stringForKey', () async { + _when('stringForKey:', ['1'], 'ok'); + expect(await userDefaults.stringForKey('1'), 'ok'); + }); + + test('setString', () async { + _whenNoResult('setString:forKey:', ['ok', '1']); + await userDefaults.setString('ok', '1'); + }); + + test('setObject', () async { + _whenNoResult('setObject:forKey:', ['ok', '1']); + await userDefaults.setObject('ok', '1'); + }); + + test('mapForKey', () async { + _when('dictionaryForKey:', ['1'], {'1': 'ok'}); + expect(await userDefaults.mapForKey('1'), {'1': 'ok'}); + }); + + test('listForKey', () async { + _when('arrayForKey:', ['1'], ['1']); + expect(await userDefaults.listForKey('1'), ['1']); + }); + + test('stringListForKey', () async { + _when>('stringArrayForKey:', ['1'], ['1']); + expect(await userDefaults.stringListForKey('1'), ['1']); + }); + + test('setUri', () async { + final uri = Uri.file('/d/d/d'); + _whenNoResult('setURL:forKey:', [uri, '1']); + await userDefaults.setUri(uri, '1'); + }); + + test('registerDefaults', () async { + _whenNoResult('registerDefaults:', [ + {'1': 'ok'} + ]); + await userDefaults.registerDefaults({'1': 'ok'}); + }); + + test('addSuite', () async { + _whenNoResult('addSuiteNamed:', ['1']); + await userDefaults.addSuite('1'); + }); + + test('removeSuite', () async { + _whenNoResult('removeSuiteNamed:', ['1']); + await userDefaults.removeSuite('1'); + }); + + test('representation', () async { + _whenNoArgs>('dictionaryRepresentation', {'1': 'ok'}); + expect(await userDefaults.representation, {'1': 'ok'}); + }); + + test('volatileDomainNames', () async { + _whenNoArgs>('volatileDomainNames', ['1']); + expect(await userDefaults.volatileDomainNames, ['1']); + }); + + test('volatileDomainNamed', () async { + _when>('volatileDomainForName:', ['1'], {'1': 'ok'}); + expect(await userDefaults.volatileDomainNamed('1'), {'1': 'ok'}); + }); + + test('setVolatileDomain', () async { + _whenNoResult('setVolatileDomain:', [ + {'1': 'ok'} + ]); + await userDefaults.setVolatileDomain({'1': 'ok'}, '1'); + }); + + test('removeVolatileDomain', () async { + _whenNoResult('removeVolatileDomainForName:', ['1']); + await userDefaults.removeVolatileDomain('1'); + }); + + test('persistentDomainNames', () async { + _whenNoArgs>('persistentDomainNames', ['1']); + expect(await userDefaults.persistentDomainNames, ['1']); + }); + + test('persistentDomainNamed', () async { + _when>('persistentDomainForName:', ['1'], {'1': 'ok'}); + expect(await userDefaults.persistentDomainNamed('1'), {'1': 'ok'}); + }); + + test('setPersistentDomain', () async { + _whenNoResult('setPersistentDomain:forName:', [ + {'1': 'ok'}, + '1' + ]); + await userDefaults.setPersistentDomain({'1': 'ok'}, '1'); + }); + + test('removePersistentDomain', () async { + _whenNoResult('removePersistentDomainForName:', ['1']); + await userDefaults.removePersistentDomain('1'); + }); + + test('synchronize', () async { + _whenNoArgs('synchronize', true); + expect(await userDefaults.synchronize(), true); + }); + + test('objectIsForcedForKey', () async { + _when('objectIsForcedForKey:inDomain:', ['1', '2'], true); + expect(await userDefaults.objectIsForcedForKey('1', domain: '2'), true); + + _when('objectIsForcedForKey:', ['1'], true); + expect(await userDefaults.objectIsForcedForKey('1'), true); + }); +}