├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .name │ ├── compiler.xml │ ├── gradle.xml │ ├── jarRepositories.xml │ ├── misc.xml │ └── modules.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── de │ └── julianassmann │ └── flutter_background │ ├── FlutterBackgroundPlugin.kt │ ├── IsolateHolderService.kt │ └── PermissionHandler.kt ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ ├── com │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── de │ │ │ │ │ └── julianassmann │ │ │ │ │ └── flutter_background_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-anydpi-v24 │ │ │ │ └── background_icon.xml │ │ │ │ ├── drawable-hdpi │ │ │ │ └── background_icon.png │ │ │ │ ├── drawable-mdpi │ │ │ │ └── background_icon.png │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-xhdpi │ │ │ │ └── background_icon.png │ │ │ │ ├── drawable-xxhdpi │ │ │ │ └── background_icon.png │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── settings_aar.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ ├── app.dart │ ├── home_page.dart │ ├── main.dart │ ├── message.dart │ ├── notification_service.dart │ ├── socket_connection_state.dart │ └── validators.dart ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── server │ └── server.dart ├── test │ └── widget_test.dart └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ └── Icon-512.png │ ├── index.html │ └── manifest.json ├── flutter_background.iml ├── images └── notification.png ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterBackgroundPlugin.h │ ├── FlutterBackgroundPlugin.m │ └── SwiftFlutterBackgroundPlugin.swift └── flutter_background.podspec ├── lib ├── flutter_background.dart └── src │ ├── android_config.dart │ └── flutter_background.dart ├── pubspec.lock ├── pubspec.yaml └── test └── flutter_background_test.dart /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report 4 | title: "[BUG] Title" 5 | labels: bug 6 | assignees: JulianAssmann 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | You must include full steps to reproduce so that we can reproduce the problem. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Smartphone:** 23 | 24 | - Device: [e.g. iPhone6] 25 | - OS: [e.g. iOS8.1] 26 | 27 |
28 | Logs 29 | 35 | ``` 36 | ``` 37 | 38 | 39 | 40 | ``` 41 | ``` 42 |
43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature Request] Title" 5 | labels: enhancement 6 | assignees: JulianAssmann 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter and Dart 2 | .DS_Store 3 | .dart_tool/ 4 | 5 | .packages 6 | .pub/ 7 | 8 | build/ 9 | 10 | # VS Code 11 | .vscode/* 12 | !.vscode/settings.json 13 | !.vscode/tasks.json 14 | !.vscode/launch.json 15 | !.vscode/extensions.json 16 | *.code-workspace 17 | 18 | # Local History for Visual Studio Code 19 | .history/ 20 | 21 | # IDEA 22 | .idea/* -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1 8 | channel: stable 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 17 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 18 | - platform: android 19 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 20 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.3.0+1 2 | 3 | * Update README to not include unecessary `` in example `AndroidManifest.xml`, as these are already defined in the plugins `AndroidManifest.xml` 4 | * Remove uncecessary double if statement in example app 5 | 6 | ## 1.3.0 7 | 8 | * **Breaking**: Support for Android 14 and above, as all foreground service must list at least one foreground service type for each service. This requires users to define 9 | * Remove references to deprecated v1 Android embedding as it will be removed in Flutter 3.26 (see the [Flutter 3.22 release notes](https://medium.com/flutter/whats-new-in-flutter-3-22-fbde6c164fe3) and the [migration guide](https://docs.flutter.dev/release/breaking-changes/plugin-api-migration)) 10 | * Move Gradle from imperative apply to declarative plugins (see [here](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) for more information) 11 | * Move the example project to a new version of the [flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications) to get the notifications running again in the latest versions of Android 12 | 13 | ## 1.2.0 14 | 15 | * Add option to hide notification badge 16 | * Add option to not request battery optimization permission 17 | * Add support for gradle 7.3+ 18 | 19 | ## 1.1.0 20 | 21 | * Add capability to enable Android Wifi Lock in the initialize function. 22 | 23 | ## 1.0.2+2 24 | 25 | * Fix crash when targeting Android S+ due to a missing immutable flag for pending intents 26 | 27 | ## 1.0.2+1 28 | 29 | * Simplified example application by removing the use of the BLoC pattern 30 | 31 | ## 1.0.2 32 | 33 | * Remove foreground service notification importance levels that cause an error on Android 34 | 35 | ## 1.0.1 36 | 37 | * Tapping on the foreground notification now launches the Flutter Activity on Android 38 | * Fix `null` Intent error for onStartCommand on Android 39 | 40 | ## 1.0.0 41 | 42 | * Add null safety 43 | 44 | ## 0.1.6 45 | 46 | * Improve initialize method on Android 47 | * Add ability to specify custom notification icons 48 | * Update documentation accordingly 49 | 50 | ## 0.1.5 51 | 52 | * Add `isBackgroundExecutionEnabled` property to enable checking the current background execution state 53 | 54 | ## 0.1.4 55 | 56 | * Fix bug where calling `FlutterBackground.initialize()` for the first time crashes the app 57 | * Fix bug where calling `FlutterBackground.hasPermissions` for the first time crashes the app 58 | * Fix some typos 59 | * Address notification icon in the documentation 60 | * Enhance error handling in example app 61 | 62 | ## 0.1.3 63 | 64 | * Stop IsolateHolderService when app is killed with swipe to remove 65 | 66 | ## 0.1.2 67 | 68 | * Fix problem where the plugin crashes when specifying the android configuration calling `FlutterBackground.initialize()` 69 | * Introduce ToDo section in the README.md 70 | * Fix some typos 71 | * Add analysis_options.yaml based on pedantic v. 1.9.0 for static analysis and conform to it 72 | * Update example app and server 73 | 74 | ## 0.1.1 75 | 76 | * Conform to dart formatting standards to improve pub.dev score 77 | 78 | ## 0.1.0 79 | 80 | * First release of the plugin for android 81 | * Add example TCP chat app 82 | * Add TCP server for the example app to talk to -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 by Julian Aßmann 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_background 2 | 3 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/julianassmann) 4 | 5 | A plugin to keep flutter apps running in the background. Currently only works with Android. 6 | 7 | It achieves this functionality by running an [Android foreground service](https://developer.android.com/guide/components/foreground-services) in combination with a [partial wake lock](https://developer.android.com/training/scheduling/wakelock#cpu) and [disabling battery optimizations](https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases) in order to keep the flutter isolate running. 8 | 9 | **Note:** This plugin currently only works with Android. 10 | PRs for iOS are very welcome, although I am not sure if a similar effect can be achieved with iOS at all. 11 | 12 | ## Getting started 13 | 14 | To use this plugin, add `flutter_background` as a [dependency in your `pubspec.yaml` file](https://pub.dev/packages/flutter_background/install). 15 | 16 | ### Android 17 | 18 | Add the following permissions to the `AndroidManifest.xml`: 19 | 20 | ```xml 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ... 30 | 31 | 32 | 36 | 37 | 38 | ``` 39 | 40 | **Important**: You must specify the appropriate `foregroundServiceType` for your use case. See the [Android docs](https://developer.android.com/about/versions/14/changes/fgs-types-required) and the [list of available service typs](https://developer.android.com/develop/background-work/services/fg-service-types) for more information on foreground service types. 41 | 42 | ### Other platforms 43 | 44 | Android is the only supported platform. There are currently no plans to extend support for other platforms, but feel free to change that by contributing to this plugin. 45 | 46 | ## Usage 47 | 48 | Import `flutter_background.dart`: 49 | 50 | ```dart 51 | import 'package:flutter_background/flutter_background.dart'; 52 | ``` 53 | 54 | ### Initializing plugin and handling permissions 55 | 56 | Before you can use this plugin, you need to initialize it by calling `FlutterBackground.initialize(...)`: 57 | 58 | ```dart 59 | final androidConfig = FlutterBackgroundAndroidConfig( 60 | notificationTitle: "flutter_background example app", 61 | notificationText: "Background notification for keeping the example app running in the background", 62 | notificationImportance: AndroidNotificationImportance.normal, 63 | notificationIcon: AndroidResource(name: 'background_icon', defType: 'drawable'), // Default is ic_launcher from folder mipmap 64 | ); 65 | bool success = await FlutterBackground.initialize(androidConfig: androidConfig); 66 | ``` 67 | 68 | This ensures all permissions are granted and requests them if necessary. It also configures the 69 | foreground notification. The configuration above results in the foreground notification shown below when 70 | running `FlutterBackground.enableBackgroundExecution()`. 71 | 72 | ![The foreground notification created by the code above.](./images/notification.png "The foreground notification created by the code above.") 73 | 74 | The arguments are: 75 | - `notificationTitle`: The title used for the foreground service notification. 76 | - `notificationText`: The body used for the foreground service notification. 77 | - `notificationImportance`: The importance of the foreground service notification. 78 | - `notificationIcon`: The icon used for the foreground service notification shown in the top left corner. This must be a drawable Android Resource (see [here](https://developer.android.com/reference/android/app/Notification.Builder#setSmallIcon(int,%20int)) for more). E. g. if the icon with name "background_icon" is in the "drawable" resource folder, it should be of value `AndroidResource(name: 'background_icon', defType: 'drawable'). 79 | - `enableWifiLock`: Indicates whether or not a WifiLock is acquired when background execution is started. This allows the application to keep the Wi-Fi radio awake, even when the user has not used the device in a while (e.g. for background network communications). 80 | 81 | In this example, `background_icon` is a drawable resource in the `drawable` folders (see the example app). 82 | For more information check out the [Android documentation for creating notification icons](https://developer.android.com/studio/write/image-asset-studio#create-notification) for more information how to create and store an icon. 83 | 84 | In order to function correctly, this plugin needs a few permissions. 85 | `FlutterBackground.initialize(...)` will request permissions from the user if necessary. 86 | You can call initialize more than one time, so you can call `initalize()` every time before you call `enableBackgroundExecution()` (see below). 87 | 88 | In order to notify the user about upcoming permission requests by the system, you need to know, whether or not the app already has these permissions. You can find out by calling 89 | 90 | ```dart 91 | bool hasPermissions = await FlutterBackground.hasPermissions; 92 | ``` 93 | before calling `FlutterBackground.initialize(...)`. If the app already has all necessary permissions, no permission requests will be displayed to the user. 94 | 95 | ### Run app in background 96 | 97 | With 98 | 99 | ```dart 100 | bool success = await FlutterBackground.enableBackgroundExecution(); 101 | ``` 102 | 103 | you can try to get the app running in the background. You must call `FlutterBackground.initialize()` before calling `FlutterBackground.enableBackgroundExecution()`. 104 | 105 | With 106 | 107 | ```dart 108 | await FlutterBackground.disableBackgroundExecution(); 109 | ``` 110 | 111 | you can stop the background execution of the app. You must call `FlutterBackground.initialize()` before calling `FlutterBackground.disableBackgroundExecution()`. 112 | 113 | To check whether background execution is currently enabled, use 114 | 115 | ```dart 116 | bool enabled = FlutterBackground.isBackgroundExecutionEnabled; 117 | ``` 118 | 119 | ## Example 120 | 121 | The example is a TCP chat app: It can connect to a TCP server and send and receive messages. The user is notified about incoming messages by notifications created with the plugin [flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications). 122 | 123 | Using this plugin, the example app can maintain the TCP connection with the server, receiving messages and creating notifications for the user even when in the background. 124 | 125 | ## Maintainer 126 | 127 | [Julian Aßmann](https://github.com/JulianAssmann) 128 | 129 | If you experience any problems with this package, please [create an issue on Github](https://github.com/JulianAssmann/flutter_background/issues). 130 | Pull requests are also very welcome. 131 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /android/.idea/.name: -------------------------------------------------------------------------------- 1 | flutter_background -------------------------------------------------------------------------------- /android/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /android/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /android/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | } 5 | 6 | group 'de.julianassmann.flutter_background' 7 | version '1.0-SNAPSHOT' 8 | 9 | android { 10 | compileSdkVersion 34 11 | 12 | compileOptions { 13 | sourceCompatibility JavaVersion.VERSION_1_8 14 | targetCompatibility JavaVersion.VERSION_1_8 15 | } 16 | 17 | kotlinOptions { 18 | jvmTarget = '1.8' 19 | } 20 | 21 | sourceSets { 22 | main.java.srcDirs += 'src/main/kotlin' 23 | } 24 | 25 | defaultConfig { 26 | minSdkVersion 16 27 | } 28 | 29 | namespace 'de.julianassmann.flutter_background' 30 | } 31 | 32 | rootProject.allprojects { 33 | repositories { 34 | google() 35 | mavenCentral() 36 | } 37 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_background' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/src/main/kotlin/de/julianassmann/flutter_background/FlutterBackgroundPlugin.kt: -------------------------------------------------------------------------------- 1 | package de.julianassmann.flutter_background 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import androidx.annotation.NonNull 7 | import androidx.core.app.NotificationCompat 8 | 9 | import io.flutter.embedding.engine.plugins.FlutterPlugin 10 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 11 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 12 | import io.flutter.plugin.common.BinaryMessenger 13 | import io.flutter.plugin.common.MethodCall 14 | import io.flutter.plugin.common.MethodChannel 15 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 16 | import io.flutter.plugin.common.MethodChannel.Result 17 | import io.flutter.plugin.common.PluginRegistry 18 | 19 | class FlutterBackgroundPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { 20 | private var methodChannel : MethodChannel? = null 21 | private var activity: Activity? = null 22 | private var permissionHandler: PermissionHandler? = null 23 | private var context: Context? = null 24 | 25 | companion object { 26 | @JvmStatic 27 | val NOTIFICATION_TITLE_KEY = "android.notificationTitle" 28 | @JvmStatic 29 | val NOTIFICATION_ICON_NAME_KEY = "android.notificationIconName" 30 | @JvmStatic 31 | val NOTIFICATION_ICON_DEF_TYPE_KEY = "android.notificationIconDefType" 32 | @JvmStatic 33 | val NOTIFICATION_TEXT_KEY = "android.notificationText" 34 | @JvmStatic 35 | val NOTIFICATION_IMPORTANCE_KEY = "android.notificationImportance" 36 | @JvmStatic 37 | val ENABLE_WIFI_LOCK_KEY = "android.enableWifiLock" 38 | @JvmStatic 39 | val SHOW_BADGE_KEY = "android.showBadge" 40 | @JvmStatic 41 | val SHOULD_REQUEST_BATTERY_OPTIMIZATIONS_OFF_KEY = "android.shouldRequestBatteryOptimizationsOff" 42 | 43 | @JvmStatic 44 | var notificationTitle: String = "flutter_background foreground service" 45 | @JvmStatic 46 | var notificationText: String = "Keeps the flutter app running in the background" 47 | @JvmStatic 48 | var notificationImportance: Int = NotificationCompat.PRIORITY_DEFAULT 49 | @JvmStatic 50 | var notificationIconName: String = "ic_launcher" 51 | @JvmStatic 52 | var notificationIconDefType: String = "mipmap" 53 | @JvmStatic 54 | var enableWifiLock: Boolean = true 55 | @JvmStatic 56 | var showBadge: Boolean = true 57 | @JvmStatic 58 | var shouldRequestBatteryOptimizationsOff: Boolean = true 59 | 60 | 61 | fun loadNotificationConfiguration(context: Context?) { 62 | val sharedPref = context?.getSharedPreferences(context.packageName + "_preferences", Context.MODE_PRIVATE) 63 | notificationTitle = sharedPref?.getString(NOTIFICATION_TITLE_KEY, notificationTitle) ?: notificationTitle 64 | notificationText = sharedPref?.getString(NOTIFICATION_TEXT_KEY, notificationText) ?: notificationText 65 | notificationImportance = sharedPref?.getInt(NOTIFICATION_IMPORTANCE_KEY, notificationImportance) ?: notificationImportance 66 | notificationIconName = sharedPref?.getString(NOTIFICATION_ICON_NAME_KEY, notificationIconName) ?: notificationIconName 67 | notificationIconDefType = sharedPref?.getString(NOTIFICATION_ICON_DEF_TYPE_KEY, notificationIconDefType) ?: notificationIconDefType 68 | enableWifiLock = sharedPref?.getBoolean(ENABLE_WIFI_LOCK_KEY, false) ?: false 69 | showBadge = sharedPref?.getBoolean(SHOW_BADGE_KEY, false) ?: false 70 | } 71 | 72 | fun saveNotificationConfiguration(context: Context?) { 73 | val sharedPref = context?.getSharedPreferences(context.packageName + "_preferences", Context.MODE_PRIVATE) 74 | with (sharedPref?.edit()) { 75 | this?.putString(NOTIFICATION_TITLE_KEY, notificationTitle) 76 | this?.putString(NOTIFICATION_TEXT_KEY, notificationText) 77 | this?.putInt(NOTIFICATION_IMPORTANCE_KEY, notificationImportance) 78 | this?.putString(NOTIFICATION_ICON_NAME_KEY, notificationIconName) 79 | this?.putString(NOTIFICATION_ICON_DEF_TYPE_KEY, notificationIconDefType) 80 | this?.putBoolean(ENABLE_WIFI_LOCK_KEY, enableWifiLock) 81 | this?.putBoolean(SHOW_BADGE_KEY, showBadge) 82 | this?.apply() 83 | } 84 | } 85 | } 86 | 87 | 88 | private fun isValidResource(context: Context, name: String, defType: String, result: Result, errorCode: String): Boolean { 89 | val resourceId = context.resources.getIdentifier(name, defType, context.packageName) 90 | if (resourceId == 0) { 91 | result.error("ResourceError", "The resource $defType/$name could not be found. Please make sure it has been added as a resource to your Android head project.", errorCode) 92 | return false 93 | } 94 | return true 95 | } 96 | 97 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { 98 | 99 | // System.out.println(call.method) 100 | // System.out.flush() 101 | 102 | when (call.method) { 103 | "getPlatformVersion" -> { 104 | result.success("Android ${android.os.Build.VERSION.RELEASE}") 105 | } 106 | "hasPermissions" -> { 107 | val hasPermissions = permissionHandler!!.isIgnoringBatteryOptimizations() 108 | && permissionHandler!!.isWakeLockPermissionGranted() 109 | result.success(hasPermissions) 110 | } 111 | "initialize" -> { 112 | val title = call.argument(NOTIFICATION_TITLE_KEY) 113 | val text = call.argument(NOTIFICATION_TEXT_KEY) 114 | val importance = call.argument(NOTIFICATION_IMPORTANCE_KEY) 115 | val iconName = call.argument(NOTIFICATION_ICON_NAME_KEY) 116 | val iconDefType = call.argument(NOTIFICATION_ICON_DEF_TYPE_KEY) 117 | val wifiLock = call.argument(ENABLE_WIFI_LOCK_KEY) 118 | val badge = call.argument(SHOW_BADGE_KEY) 119 | val requestBatteryOptimizationsOff = call.argument(SHOULD_REQUEST_BATTERY_OPTIMIZATIONS_OFF_KEY) 120 | 121 | // Set static values so the IsolateHolderService can use them later on to configure the notification 122 | notificationImportance = importance ?: notificationImportance 123 | notificationTitle = title ?: notificationTitle 124 | notificationText = text ?: notificationText 125 | notificationIconName = iconName ?: notificationIconName 126 | notificationIconDefType = iconDefType ?: notificationIconDefType 127 | enableWifiLock = wifiLock ?: enableWifiLock 128 | showBadge = badge ?: showBadge 129 | shouldRequestBatteryOptimizationsOff = requestBatteryOptimizationsOff ?: shouldRequestBatteryOptimizationsOff 130 | 131 | saveNotificationConfiguration(context) 132 | 133 | if (permissionHandler!!.isWakeLockPermissionGranted() && (!shouldRequestBatteryOptimizationsOff || permissionHandler!!.isIgnoringBatteryOptimizations())) { 134 | result.success(true) 135 | return 136 | } 137 | 138 | // Ensure wake lock permissions are granted 139 | if (!permissionHandler!!.isWakeLockPermissionGranted()) { 140 | result.error("PermissionError", "Please add the WAKE_LOCK permission to the AndroidManifest.xml in order to use background_sockets.", "") 141 | return 142 | } 143 | 144 | // Ensure ignoring battery optimizations is enabled if requested 145 | if (shouldRequestBatteryOptimizationsOff && !permissionHandler!!.isIgnoringBatteryOptimizations()) { 146 | if (activity != null) { 147 | permissionHandler!!.requestBatteryOptimizationsOff(result, activity!!) 148 | } else { 149 | result.error("NoActivityError", "The plugin is not attached to an activity", "The plugin is not attached to an activity. This is required in order to request battery optimization to be off.") 150 | } 151 | } 152 | } 153 | "enableBackgroundExecution" -> { 154 | // Ensure all the necessary permissions are granted 155 | if (!permissionHandler!!.isWakeLockPermissionGranted()) { 156 | result.error("PermissionError", "Please add the WAKE_LOCK permission to the AndroidManifest.xml in order to use background_sockets.", "") 157 | return 158 | } else if (shouldRequestBatteryOptimizationsOff && !permissionHandler!!.isIgnoringBatteryOptimizations()) { 159 | result.error("PermissionError", "The battery optimizations are not turned off.", "") 160 | } else { 161 | val intent = Intent(context, IsolateHolderService::class.java) 162 | intent.action = IsolateHolderService.ACTION_START 163 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 164 | context!!.startForegroundService(intent) 165 | } else { 166 | context!!.startService(intent) 167 | } 168 | result.success(true) 169 | } 170 | } 171 | "disableBackgroundExecution" -> { 172 | val intent = Intent(context!!, IsolateHolderService::class.java) 173 | intent.action = IsolateHolderService.ACTION_SHUTDOWN 174 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 175 | context!!.startForegroundService(intent) 176 | } else { 177 | context!!.startService(intent) 178 | } 179 | result.success(true) 180 | } 181 | else -> { 182 | result.notImplemented() 183 | } 184 | } 185 | } 186 | 187 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { 188 | startListening(binding.applicationContext, binding.binaryMessenger) 189 | } 190 | 191 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 192 | stopListening() 193 | } 194 | 195 | override fun onDetachedFromActivity() { 196 | stopListeningToActivity() 197 | } 198 | 199 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { 200 | onAttachedToActivity(binding) 201 | } 202 | 203 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 204 | startListeningToActivity( 205 | binding.activity, 206 | binding::addActivityResultListener, 207 | binding::addRequestPermissionsResultListener) 208 | } 209 | 210 | override fun onDetachedFromActivityForConfigChanges() { 211 | onDetachedFromActivity() 212 | } 213 | 214 | private fun startListening(applicationContext: Context, messenger: BinaryMessenger) { 215 | methodChannel = MethodChannel( 216 | messenger, 217 | "flutter_background" 218 | ) 219 | methodChannel!!.setMethodCallHandler(this) 220 | context = applicationContext 221 | } 222 | 223 | private fun stopListening() { 224 | methodChannel!!.setMethodCallHandler(null) 225 | methodChannel = null 226 | context = null 227 | } 228 | 229 | private fun startListeningToActivity( 230 | activity: Activity, 231 | addActivityResultListener: ((PluginRegistry.ActivityResultListener) -> Unit), 232 | addRequestPermissionResultListener: ((PluginRegistry.RequestPermissionsResultListener) -> Unit) 233 | ) { 234 | this.activity = activity 235 | permissionHandler = PermissionHandler( 236 | activity.applicationContext, 237 | addActivityResultListener, 238 | addRequestPermissionResultListener) 239 | } 240 | 241 | private fun stopListeningToActivity() { 242 | this.activity = null 243 | permissionHandler = null 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /android/src/main/kotlin/de/julianassmann/flutter_background/IsolateHolderService.kt: -------------------------------------------------------------------------------- 1 | package de.julianassmann.flutter_background 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.NotificationChannel 5 | import android.app.NotificationManager 6 | import android.app.PendingIntent 7 | import android.app.Service 8 | import android.content.Context 9 | import android.content.Intent 10 | import android.content.pm.ServiceInfo 11 | import android.net.wifi.WifiManager 12 | import android.os.Build 13 | import android.os.IBinder 14 | import android.os.PowerManager 15 | import androidx.core.app.NotificationCompat 16 | 17 | class IsolateHolderService : Service() { 18 | companion object { 19 | @JvmStatic 20 | val ACTION_SHUTDOWN = "SHUTDOWN" 21 | @JvmStatic 22 | val ACTION_START = "START" 23 | @JvmStatic 24 | val WAKELOCK_TAG = "FlutterBackgroundPlugin:Wakelock" 25 | @JvmStatic 26 | val WIFILOCK_TAG = "FlutterBackgroundPlugin:WifiLock" 27 | @JvmStatic 28 | val CHANNEL_ID = "flutter_background" 29 | @JvmStatic 30 | private val TAG = "IsolateHolderService" 31 | } 32 | 33 | private var wakeLock: PowerManager.WakeLock? = null 34 | private var wifiLock: WifiManager.WifiLock? = null 35 | 36 | override fun onBind(intent: Intent) : IBinder? { 37 | return null 38 | } 39 | 40 | override fun onCreate() { 41 | FlutterBackgroundPlugin.loadNotificationConfiguration(applicationContext) 42 | } 43 | 44 | override fun onDestroy() { 45 | cleanupService() 46 | super.onDestroy() 47 | } 48 | 49 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) : Int { 50 | if (intent?.action == ACTION_SHUTDOWN) { 51 | cleanupService() 52 | stopSelf() 53 | } else if (intent?.action == ACTION_START) { 54 | startService() 55 | } 56 | return START_STICKY 57 | } 58 | 59 | private fun cleanupService() { 60 | wakeLock?.apply { 61 | if (isHeld) { 62 | release() 63 | } 64 | } 65 | 66 | if (FlutterBackgroundPlugin.enableWifiLock) { 67 | wifiLock?.apply { 68 | if (isHeld) { 69 | release() 70 | } 71 | } 72 | } 73 | 74 | stopForeground(true) 75 | } 76 | 77 | @SuppressLint("WakelockTimeout") 78 | private fun startService() { 79 | val pm = applicationContext.packageManager 80 | val notificationIntent = 81 | pm.getLaunchIntentForPackage(applicationContext.packageName) 82 | 83 | // See https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent 84 | var flags = PendingIntent.FLAG_UPDATE_CURRENT 85 | if (Build.VERSION.SDK_INT > 23) flags = flags or PendingIntent.FLAG_IMMUTABLE 86 | 87 | val pendingIntent = PendingIntent.getActivity( 88 | this, 0, 89 | notificationIntent, flags 90 | ) 91 | 92 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 93 | val channel = NotificationChannel( 94 | CHANNEL_ID, 95 | FlutterBackgroundPlugin.notificationTitle, 96 | FlutterBackgroundPlugin.notificationImportance).apply { 97 | description = FlutterBackgroundPlugin.notificationText 98 | } 99 | channel.setShowBadge(FlutterBackgroundPlugin.showBadge) 100 | // Register the channel with the system 101 | val notificationManager: NotificationManager = 102 | getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 103 | notificationManager.createNotificationChannel(channel) 104 | } 105 | 106 | val imageId = resources.getIdentifier(FlutterBackgroundPlugin.notificationIconName, FlutterBackgroundPlugin.notificationIconDefType, packageName) 107 | val notification = NotificationCompat.Builder(this, CHANNEL_ID) 108 | .setContentTitle(FlutterBackgroundPlugin.notificationTitle) 109 | .setContentText(FlutterBackgroundPlugin.notificationText) 110 | .setSmallIcon(imageId) 111 | .setContentIntent(pendingIntent) 112 | .setPriority(FlutterBackgroundPlugin.notificationImportance) 113 | .build() 114 | 115 | (getSystemService(Context.POWER_SERVICE) as PowerManager).run { 116 | wakeLock = newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG).apply { 117 | setReferenceCounted(false) 118 | acquire() 119 | } 120 | } 121 | 122 | (applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager).run { 123 | wifiLock = createWifiLock(WifiManager.WIFI_MODE_FULL, WIFILOCK_TAG).apply { 124 | setReferenceCounted(false) 125 | acquire() 126 | } 127 | } 128 | 129 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 130 | // Use all foreground service types set in the manifest file 131 | startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST); 132 | } else { 133 | startForeground(1, notification) 134 | } 135 | } 136 | 137 | override fun onTaskRemoved(rootIntent: Intent) { 138 | super.onTaskRemoved(rootIntent) 139 | cleanupService() 140 | stopSelf() 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /android/src/main/kotlin/de/julianassmann/flutter_background/PermissionHandler.kt: -------------------------------------------------------------------------------- 1 | package de.julianassmann.flutter_background 2 | 3 | import android.Manifest 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.content.pm.PackageManager 8 | import android.net.Uri 9 | import android.os.Build 10 | import android.os.PowerManager 11 | import android.provider.Settings 12 | import io.flutter.plugin.common.MethodChannel 13 | import io.flutter.plugin.common.PluginRegistry 14 | 15 | class PermissionHandler(private val context: Context, 16 | private val addActivityResultListener: ((PluginRegistry.ActivityResultListener) -> Unit), 17 | private val addRequestPermissionsResultListener: ((PluginRegistry.RequestPermissionsResultListener) -> Unit)) { 18 | companion object { 19 | const val PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS = 5672353 20 | } 21 | 22 | fun isWakeLockPermissionGranted(): Boolean 23 | { 24 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 25 | context.checkSelfPermission(Manifest.permission.WAKE_LOCK) == PackageManager.PERMISSION_GRANTED 26 | } else { 27 | true 28 | }; 29 | } 30 | 31 | fun isIgnoringBatteryOptimizations(): Boolean { 32 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 33 | val powerManager = (context.getSystemService(Context.POWER_SERVICE) as PowerManager) 34 | powerManager.isIgnoringBatteryOptimizations(context.packageName) 35 | } else { 36 | // Before Android M, the battery optimization doesn't exist -> Always "ignoring" 37 | true 38 | } 39 | } 40 | 41 | fun requestBatteryOptimizationsOff( 42 | result: MethodChannel.Result, 43 | activity: Activity) { 44 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 45 | // Before Android M the battery optimization doesn't exist -> Always "ignoring" 46 | result.success(true) 47 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 48 | val powerManager = (context.getSystemService(Context.POWER_SERVICE) as PowerManager) 49 | when { 50 | powerManager.isIgnoringBatteryOptimizations(context.packageName) -> { 51 | result.success(true) 52 | } 53 | context.checkSelfPermission(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) == PackageManager.PERMISSION_DENIED -> { 54 | result.error( 55 | "flutter_background.PermissionHandler", 56 | "The app does not have the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission required to ask the user for whitelisting. See the documentation on how to setup this plugin properly.", 57 | null) 58 | } 59 | else -> { 60 | addActivityResultListener(PermissionActivityResultListener(result::success, result::error)) 61 | val intent = Intent() 62 | intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 63 | intent.data = Uri.parse("package:${context.packageName}") 64 | activity.startActivityForResult(intent, PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS) 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | class PermissionActivityResultListener( 72 | private val onSuccess: (Any?) -> Unit, 73 | private val onError: (String, String?, Any?) -> Unit) : PluginRegistry.ActivityResultListener { 74 | 75 | private var alreadyCalled: Boolean = false; 76 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { 77 | try { 78 | if (alreadyCalled || requestCode != PermissionHandler.PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS) { 79 | return false 80 | } 81 | 82 | alreadyCalled = true 83 | 84 | onSuccess(resultCode == Activity.RESULT_OK) 85 | } catch (ex: Exception) { 86 | onError("flutter_background.PermissionHandler", "Error while waiting for user to disable battery optimizations", ex.localizedMessage) 87 | } 88 | 89 | return true 90 | } 91 | } -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_background example 2 | 3 | This app demonstrantes the use of the flutter_background plugin. 4 | For demonstration purposes it uses TCP sockets to 'chats' with a TCP server. 5 | 6 | The app allows the user to create a TCP connection to a TCP server identified by a hostname and a port the user can enter. A chat-like UI allows to receive messages from and send messages to the server. The user is notified about incoming messages by creating notifications using [flutter_local_notifications](https://github.com/MaikuB/flutter_local_notifications). 7 | 8 | Using the `flutter_background` plugin, the app continues to receive messages from the server when running in the background. 9 | 10 | The `server` folder contains a very simple TCP server that accepts incoming connections. It shows incoming messages from the client and sends messages written in the terminal to the client. Additionally it sends messages to the client in an interval of 5 seconds in order to demonstrate, that the app can receive messages even when running in the background. 11 | 12 | ## Requirements 13 | 14 | You need to have the following tools installed: 15 | 16 | - [Flutter](https://flutter.dev/docs/get-started/install) 17 | 18 | ## Run 19 | 20 | To start the server, go into the `server` folder and run 21 | 22 | ```bash 23 | dart server.dart 24 | ``` 25 | 26 | To start the app, go into the `app` folder and run 27 | 28 | ```bash 29 | flutter run 30 | ``` 31 | 32 | ## Configuration 33 | 34 | In the server file (`server/server.dart`) you can configure the hostname and port of the TCP server by setting the `const` values `hostname` and `port`. 35 | 36 | If you run the app in the Android Emulator, set the `hostname` in `server.dart` to `localhost` and input the IP address `10.0.2.2` (the hosts IP address from inside the Android Emulator) in the app. 37 | 38 | If you run the app on a real device, set the `hostname` in `server.dart` and in the client app to the IP address of the machine in the local network (obtained via `ifconfig` (Linux/Mac OS) or `ipconfig` (Windows)). 39 | 40 | The ports specified in the server and the app must be the same. 41 | 42 | ## Tools used 43 | 44 | - [Flutter](https://flutter.dev/) 45 | - [bubble](https://github.com/vi-k/bubble) 46 | - [flutter_local_notifications](https://github.com/MaikuB/flutter_local_notifications) -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | compileSdkVersion flutter.compileSdkVersion 27 | ndkVersion flutter.ndkVersion 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | defaultConfig { 43 | applicationId "de.julianassmann.flutter_background_example" 44 | minSdkVersion flutter.minSdkVersion 45 | targetSdkVersion flutter.targetSdkVersion 46 | versionCode flutterVersionCode.toInteger() 47 | versionName flutterVersionName 48 | } 49 | 50 | buildTypes { 51 | release { 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | // Version 10+ of flutter_local_notifications relies on desguaring to support scheduled notifications with backwards compatibility on older versions of Android. 62 | dependencies { 63 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' 64 | } -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/de/julianassmann/flutter_background_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package de.julianassmann.flutter_background_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-anydpi-v24/background_icon.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-hdpi/background_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/drawable-hdpi/background_icon.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-mdpi/background_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/drawable-mdpi/background_icon.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-xhdpi/background_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/drawable-xhdpi/background_icon.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-xxhdpi/background_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/drawable-xxhdpi/background_icon.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.1" apply false 22 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 23 | } 24 | 25 | include ":app" -------------------------------------------------------------------------------- /example/android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'home_page.dart'; 4 | 5 | class App extends StatelessWidget { 6 | const App({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'flutter_background demo', 12 | theme: ThemeData( 13 | primarySwatch: Colors.blue, 14 | ), 15 | home: const HomePage(), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/lib/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:bubble/bubble.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_background/flutter_background.dart'; 7 | import 'package:flutter_background_example/message.dart'; 8 | import 'package:flutter_background_example/socket_connection_state.dart'; 9 | import 'package:flutter_background_example/validators.dart'; 10 | 11 | import 'notification_service.dart'; 12 | 13 | class HomePage extends StatefulWidget { 14 | const HomePage({Key? key}) : super(key: key); 15 | 16 | @override 17 | _HomePageState createState() => _HomePageState(); 18 | } 19 | 20 | class _HomePageState extends State { 21 | TextEditingController? _hostEditingController; 22 | TextEditingController? _portEditingController; 23 | TextEditingController? _chatTextEditingController; 24 | Timer? _timer; 25 | int _timerTotalSeconds = 0; 26 | 27 | List _messages = []; 28 | 29 | Socket? _socket; 30 | StreamSubscription? _socketStreamSub; 31 | SocketConnectionState _state = SocketConnectionState.none; 32 | 33 | final _formKey = GlobalKey(); 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | 39 | _hostEditingController = TextEditingController(text: '10.0.2.2'); 40 | _portEditingController = TextEditingController(text: '6666'); 41 | _chatTextEditingController = TextEditingController(text: ''); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | appBar: AppBar(title: const Text('flutter_background exmaple'), actions: [ 48 | IconButton( 49 | icon: const Icon(Icons.info_outline), 50 | onPressed: () { 51 | showAboutDialog( 52 | applicationName: 'flutter_background example', 53 | context: context); 54 | }, 55 | ) 56 | ]), 57 | body: _buildBody(), 58 | ); 59 | } 60 | 61 | Widget _buildBody() { 62 | switch (_state) { 63 | case SocketConnectionState.none: 64 | return _buildConnectionDetails(); 65 | case SocketConnectionState.connecting: 66 | return const Text('Connecting'); 67 | case SocketConnectionState.connected: 68 | return _buildChat(); 69 | case SocketConnectionState.failed: 70 | ScaffoldMessenger.of(context).showSnackBar(const SnackBar( 71 | content: Text('Connection failed'), 72 | backgroundColor: Colors.red, 73 | duration: Duration(seconds: 3))); 74 | setState(() { 75 | _state = SocketConnectionState.none; 76 | }); 77 | return Container(); 78 | case SocketConnectionState.disconnecting: 79 | return const Text('Disconnecting'); 80 | } 81 | } 82 | 83 | /// Builds the UI that allows for filling in the connection details 84 | /// (IP address, port) and initiate the connection. 85 | Widget _buildConnectionDetails() { 86 | return Padding( 87 | padding: const EdgeInsets.all(8.0), 88 | child: Form( 89 | key: _formKey, 90 | child: Column(children: [ 91 | TextFormField( 92 | controller: _hostEditingController, 93 | autovalidateMode: AutovalidateMode.always, 94 | validator: (str) => isValidHost(str) ? null : 'Invalid hostname', 95 | decoration: const InputDecoration( 96 | helperText: 'The IP address or hostname of the TCP server', 97 | hintText: 'Enter the address here, e.g. 10.0.2.2', 98 | ), 99 | ), 100 | TextFormField( 101 | controller: _portEditingController, 102 | autovalidateMode: AutovalidateMode.always, 103 | validator: (str) => isValidPort(str) ? null : 'Invalid port', 104 | decoration: const InputDecoration( 105 | helperText: 'The port the TCP server is listening on', 106 | hintText: 'Enter the port here, e. g. 6666', 107 | ), 108 | ), 109 | ElevatedButton( 110 | onPressed: _state == SocketConnectionState.none 111 | ? () { 112 | if (_formKey.currentState!.validate()) { 113 | _connectToServer(_hostEditingController!.text, 114 | int.parse(_portEditingController!.text)); 115 | } 116 | } 117 | : null, 118 | child: const Text('Connect')), 119 | ])), 120 | ); 121 | } 122 | 123 | /// Builds the UI that allows to chat. 124 | Widget _buildChat() { 125 | return Column(children: [ 126 | Expanded( 127 | child: ListView.builder( 128 | itemCount: _messages.length, 129 | itemBuilder: (context, idx) { 130 | final m = _messages[idx]; 131 | return Bubble( 132 | alignment: 133 | m.sender ? Alignment.centerRight : Alignment.centerLeft, 134 | child: Text(m.text), 135 | ); 136 | }), 137 | ), 138 | Padding( 139 | padding: const EdgeInsets.all(8.0), 140 | child: Row( 141 | children: [ 142 | Expanded( 143 | child: TextField( 144 | decoration: const InputDecoration(hintText: 'Message'), 145 | controller: _chatTextEditingController, 146 | ), 147 | ), 148 | IconButton( 149 | icon: const Icon(Icons.send), 150 | onPressed: () { 151 | if (_chatTextEditingController!.text.isNotEmpty) { 152 | final message = 153 | Message(_chatTextEditingController!.text, true); 154 | _socket!.write(message.text); 155 | _chatTextEditingController!.text = ''; 156 | setState(() { 157 | _messages = _messages.toList()..add(message); 158 | }); 159 | } 160 | }) 161 | ], 162 | ), 163 | ), 164 | ElevatedButton( 165 | child: const Text('Disconnect'), 166 | onPressed: () { 167 | _disconnectFromServer(); 168 | }, 169 | ) 170 | ]); 171 | } 172 | 173 | Future _connectToServer(String host, int port) async { 174 | // Request permissions to show notifications when messages are received 175 | await NotificationService().initialize(); 176 | 177 | // Request permissions for the flutter_background config 178 | const config = FlutterBackgroundAndroidConfig( 179 | notificationTitle: 'flutter_background example app', 180 | notificationText: 181 | 'Background notification for keeping the example app running in the background', 182 | notificationIcon: AndroidResource(name: 'background_icon'), 183 | notificationImportance: AndroidNotificationImportance.normal, 184 | enableWifiLock: true, 185 | showBadge: true, 186 | ); 187 | 188 | var hasPermissions = await FlutterBackground.hasPermissions; 189 | if (!hasPermissions) { 190 | await showDialog( 191 | context: context, 192 | builder: (context) { 193 | return AlertDialog( 194 | title: const Text('Permissions needed'), 195 | content: const Text( 196 | 'Shortly the OS will ask you for permission to execute this app in the background. This is required in order to receive chat messages when the app is not in the foreground.'), 197 | actions: [ 198 | TextButton( 199 | onPressed: () => Navigator.pop(context, 'OK'), 200 | child: const Text('OK'), 201 | ), 202 | ]); 203 | }); 204 | } 205 | 206 | hasPermissions = await FlutterBackground.initialize(androidConfig: config); 207 | 208 | if (hasPermissions) { 209 | final backgroundExecution = 210 | await FlutterBackground.enableBackgroundExecution(); 211 | if (backgroundExecution) { 212 | try { 213 | setState(() { 214 | _state = SocketConnectionState.connecting; 215 | }); 216 | 217 | _socket = await Socket.connect(host, port); 218 | _socketStreamSub = _socket!.asBroadcastStream().listen((data) async { 219 | final message = 220 | 'Message from server: ${String.fromCharCodes(data)}'; 221 | print(message); 222 | await NotificationService().newNotification(message, false); 223 | setState(() { 224 | _messages = _messages.toList()..add(Message(message, false)); 225 | }); 226 | 227 | _timer?.cancel(); 228 | _timer = Timer(const Duration(seconds: 60), () { 229 | _timerTotalSeconds += _timer!.tick; 230 | 231 | _timerTotalSeconds += 10; 232 | 233 | final hours = _timerTotalSeconds ~/ 3600; 234 | final minutes = (_timerTotalSeconds ~/ 60) % 60; 235 | final seconds = _timerTotalSeconds % 60; 236 | final message = 237 | 'Background service alive for ${hours}h ${minutes}m ${seconds}s'; 238 | 239 | _messages = _messages.toList()..add(Message(message, false)); 240 | }); 241 | }, onError: (err) { 242 | print(err); 243 | setState(() { 244 | _state = SocketConnectionState.failed; 245 | }); 246 | _disconnectFromServer(); 247 | }, onDone: () { 248 | setState(() { 249 | _state = SocketConnectionState.failed; 250 | }); 251 | _disconnectFromServer(); 252 | }, cancelOnError: true); 253 | 254 | setState(() { 255 | _state = SocketConnectionState.connected; 256 | }); 257 | } catch (ex) { 258 | print(ex); 259 | _socket?.close(); 260 | _socketStreamSub?.cancel(); 261 | _socket = null; 262 | _socketStreamSub = null; 263 | setState(() { 264 | _state = SocketConnectionState.failed; 265 | }); 266 | } 267 | } 268 | } 269 | } 270 | 271 | Future _disconnectFromServer() async { 272 | setState(() { 273 | _state = SocketConnectionState.disconnecting; 274 | }); 275 | 276 | await _socketStreamSub?.cancel(); 277 | await _socket?.close(); 278 | await FlutterBackground.disableBackgroundExecution(); 279 | _socket = null; 280 | _socketStreamSub = null; 281 | 282 | setState(() { 283 | _messages = []; 284 | _state = SocketConnectionState.none; 285 | }); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'app.dart'; 4 | 5 | void main() { 6 | runApp(const App()); 7 | } 8 | -------------------------------------------------------------------------------- /example/lib/message.dart: -------------------------------------------------------------------------------- 1 | class Message { 2 | /// Indicates whether or not this client is the sender or not. 3 | /// `true` means that this client was the sender, 4 | /// `false` means that the message was received. 5 | final bool sender; 6 | 7 | /// The text message. 8 | final String text; 9 | 10 | /// Creates a new messsage. 11 | /// 12 | /// [text] is the actual message. 13 | /// [sender] indicates, whether this client is the sender or not. 14 | Message(this.text, this.sender); 15 | } 16 | -------------------------------------------------------------------------------- /example/lib/notification_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 4 | 5 | @pragma('vm:entry-point') 6 | void notificationTapBackground(NotificationResponse notificationResponse) { 7 | debugPrint("Notification tapped in background: ${notificationResponse.payload}"); 8 | } 9 | 10 | /// The service used to display notifications and handle callbacks when the user taps on the notification. 11 | /// 12 | /// This is a singleton. Just call NotificationService() to get the singleton. 13 | class NotificationService { 14 | static final NotificationService _instance = NotificationService._internal(); 15 | 16 | factory NotificationService() => _instance; 17 | 18 | late FlutterLocalNotificationsPlugin plugin; 19 | 20 | NotificationService._internal() { 21 | plugin = FlutterLocalNotificationsPlugin(); 22 | _initializeSettings(); 23 | } 24 | 25 | Future _initializeSettings() async { 26 | const initializationSettingsAndroid = 27 | AndroidInitializationSettings('@mipmap/ic_launcher'); 28 | final initializationSettingsDarwin = DarwinInitializationSettings( 29 | requestAlertPermission: true, 30 | requestBadgePermission: true, 31 | requestSoundPermission: true, 32 | onDidReceiveLocalNotification: 33 | (int id, String? title, String? body, String? payload) async { 34 | debugPrint('Received iOS notification: $id, $title, $body, $payload'); 35 | }, 36 | ); 37 | 38 | final initializationSettings = InitializationSettings( 39 | android: initializationSettingsAndroid, 40 | iOS: initializationSettingsDarwin, 41 | ); 42 | 43 | await plugin.initialize( 44 | initializationSettings, 45 | onDidReceiveNotificationResponse: (NotificationResponse notificationResponse) async { 46 | debugPrint('Notification received: ${notificationResponse.payload}'); 47 | }, 48 | onDidReceiveBackgroundNotificationResponse: notificationTapBackground, 49 | ); 50 | 51 | await _requestPermissions(); 52 | } 53 | 54 | Future _requestPermissions() async { 55 | // For Android 56 | await plugin 57 | .resolvePlatformSpecificImplementation< 58 | AndroidFlutterLocalNotificationsPlugin>()?.requestNotificationsPermission(); 59 | 60 | // For iOS 61 | await plugin 62 | .resolvePlatformSpecificImplementation< 63 | IOSFlutterLocalNotificationsPlugin>() 64 | ?.requestPermissions( 65 | alert: true, 66 | badge: true, 67 | sound: true, 68 | ); 69 | } 70 | 71 | Future initialize() async { 72 | _instance._requestPermissions(); 73 | } 74 | 75 | Future newNotification(String msg, bool vibration) async { 76 | // Define vibration pattern 77 | var vibrationPattern = Int64List(4); 78 | vibrationPattern[0] = 0; 79 | vibrationPattern[1] = 1000; 80 | vibrationPattern[2] = 5000; 81 | vibrationPattern[3] = 2000; 82 | 83 | const channelName = 'Text messages'; 84 | 85 | final androidNotificationDetails = AndroidNotificationDetails( 86 | channelName, 87 | channelName, 88 | channelDescription: channelName, 89 | importance: Importance.max, 90 | priority: Priority.high, 91 | vibrationPattern: vibration ? vibrationPattern : null, 92 | enableVibration: vibration, 93 | visibility: NotificationVisibility.public, 94 | ); 95 | 96 | const darwinNotificationDetails = DarwinNotificationDetails(); 97 | final notificationDetails = NotificationDetails( 98 | android: androidNotificationDetails, 99 | iOS: darwinNotificationDetails, 100 | ); 101 | 102 | try { 103 | await plugin.show(0, 'New Message', msg, notificationDetails, payload: msg); 104 | } catch (ex) { 105 | debugPrint('Error showing notification: $ex'); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /example/lib/socket_connection_state.dart: -------------------------------------------------------------------------------- 1 | enum SocketConnectionState { 2 | connecting, 3 | disconnecting, 4 | connected, 5 | failed, 6 | none 7 | } 8 | -------------------------------------------------------------------------------- /example/lib/validators.dart: -------------------------------------------------------------------------------- 1 | /// Validates Hostname 2 | bool isValidHost(String? str) { 3 | if (str == null || str.isEmpty) return false; 4 | final ipAddressExp = RegExp( 5 | r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'); 6 | final hostnameExp = RegExp( 7 | r'^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'); 8 | return ipAddressExp.hasMatch(str) || hostnameExp.hasMatch(str); 9 | } 10 | 11 | /// Validates a TCP port 12 | bool isValidPort(String? str) { 13 | if (str == null || str.isEmpty) return false; 14 | final regex = RegExp( 15 | r'^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$'); 16 | return regex.hasMatch(str); 17 | } 18 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import flutter_local_notifications 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /example/macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - flutter_local_notifications (0.0.1): 3 | - FlutterMacOS 4 | - FlutterMacOS (1.0.0) 5 | 6 | DEPENDENCIES: 7 | - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) 8 | - FlutterMacOS (from `Flutter/ephemeral`) 9 | 10 | EXTERNAL SOURCES: 11 | flutter_local_notifications: 12 | :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos 13 | FlutterMacOS: 14 | :path: Flutter/ephemeral 15 | 16 | SPEC CHECKSUMS: 17 | flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 18 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 19 | 20 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 21 | 22 | COCOAPODS: 1.10.1 23 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 71 | 73 | 79 | 80 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/macos/Runner/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | args: 5 | dependency: transitive 6 | description: 7 | name: args 8 | sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.5.0" 12 | async: 13 | dependency: transitive 14 | description: 15 | name: async 16 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.11.0" 20 | boolean_selector: 21 | dependency: transitive 22 | description: 23 | name: boolean_selector 24 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.1.1" 28 | bubble: 29 | dependency: "direct main" 30 | description: 31 | name: bubble 32 | sha256: "65b992b8f8ba2e7e2871190cbdfaa0818b6de2f340bef37cb5ee1b61debe0226" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.2.1" 36 | characters: 37 | dependency: transitive 38 | description: 39 | name: characters 40 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.3.0" 44 | clock: 45 | dependency: transitive 46 | description: 47 | name: clock 48 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.1.1" 52 | collection: 53 | dependency: transitive 54 | description: 55 | name: collection 56 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.18.0" 60 | dbus: 61 | dependency: transitive 62 | description: 63 | name: dbus 64 | sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "0.7.10" 68 | fake_async: 69 | dependency: transitive 70 | description: 71 | name: fake_async 72 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.3.1" 76 | ffi: 77 | dependency: transitive 78 | description: 79 | name: ffi 80 | sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "2.1.3" 84 | flutter: 85 | dependency: "direct main" 86 | description: flutter 87 | source: sdk 88 | version: "0.0.0" 89 | flutter_background: 90 | dependency: "direct main" 91 | description: 92 | path: ".." 93 | relative: true 94 | source: path 95 | version: "1.3.0+1" 96 | flutter_local_notifications: 97 | dependency: "direct main" 98 | description: 99 | name: flutter_local_notifications 100 | sha256: c500d5d9e7e553f06b61877ca6b9c8b92c570a4c8db371038702e8ce57f8a50f 101 | url: "https://pub.dev" 102 | source: hosted 103 | version: "17.2.2" 104 | flutter_local_notifications_linux: 105 | dependency: transitive 106 | description: 107 | name: flutter_local_notifications_linux 108 | sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af 109 | url: "https://pub.dev" 110 | source: hosted 111 | version: "4.0.1" 112 | flutter_local_notifications_platform_interface: 113 | dependency: transitive 114 | description: 115 | name: flutter_local_notifications_platform_interface 116 | sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" 117 | url: "https://pub.dev" 118 | source: hosted 119 | version: "7.2.0" 120 | flutter_test: 121 | dependency: "direct dev" 122 | description: flutter 123 | source: sdk 124 | version: "0.0.0" 125 | leak_tracker: 126 | dependency: transitive 127 | description: 128 | name: leak_tracker 129 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" 130 | url: "https://pub.dev" 131 | source: hosted 132 | version: "10.0.5" 133 | leak_tracker_flutter_testing: 134 | dependency: transitive 135 | description: 136 | name: leak_tracker_flutter_testing 137 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" 138 | url: "https://pub.dev" 139 | source: hosted 140 | version: "3.0.5" 141 | leak_tracker_testing: 142 | dependency: transitive 143 | description: 144 | name: leak_tracker_testing 145 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 146 | url: "https://pub.dev" 147 | source: hosted 148 | version: "3.0.1" 149 | matcher: 150 | dependency: transitive 151 | description: 152 | name: matcher 153 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 154 | url: "https://pub.dev" 155 | source: hosted 156 | version: "0.12.16+1" 157 | material_color_utilities: 158 | dependency: transitive 159 | description: 160 | name: material_color_utilities 161 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 162 | url: "https://pub.dev" 163 | source: hosted 164 | version: "0.11.1" 165 | meta: 166 | dependency: transitive 167 | description: 168 | name: meta 169 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 170 | url: "https://pub.dev" 171 | source: hosted 172 | version: "1.15.0" 173 | path: 174 | dependency: transitive 175 | description: 176 | name: path 177 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 178 | url: "https://pub.dev" 179 | source: hosted 180 | version: "1.9.0" 181 | petitparser: 182 | dependency: transitive 183 | description: 184 | name: petitparser 185 | sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 186 | url: "https://pub.dev" 187 | source: hosted 188 | version: "6.0.2" 189 | plugin_platform_interface: 190 | dependency: transitive 191 | description: 192 | name: plugin_platform_interface 193 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 194 | url: "https://pub.dev" 195 | source: hosted 196 | version: "2.1.8" 197 | sky_engine: 198 | dependency: transitive 199 | description: flutter 200 | source: sdk 201 | version: "0.0.99" 202 | source_span: 203 | dependency: transitive 204 | description: 205 | name: source_span 206 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "1.10.0" 210 | stack_trace: 211 | dependency: transitive 212 | description: 213 | name: stack_trace 214 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "1.11.1" 218 | stream_channel: 219 | dependency: transitive 220 | description: 221 | name: stream_channel 222 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "2.1.2" 226 | string_scanner: 227 | dependency: transitive 228 | description: 229 | name: string_scanner 230 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "1.2.0" 234 | term_glyph: 235 | dependency: transitive 236 | description: 237 | name: term_glyph 238 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "1.2.1" 242 | test_api: 243 | dependency: transitive 244 | description: 245 | name: test_api 246 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" 247 | url: "https://pub.dev" 248 | source: hosted 249 | version: "0.7.2" 250 | timezone: 251 | dependency: transitive 252 | description: 253 | name: timezone 254 | sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" 255 | url: "https://pub.dev" 256 | source: hosted 257 | version: "0.9.4" 258 | vector_math: 259 | dependency: transitive 260 | description: 261 | name: vector_math 262 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 263 | url: "https://pub.dev" 264 | source: hosted 265 | version: "2.1.4" 266 | vm_service: 267 | dependency: transitive 268 | description: 269 | name: vm_service 270 | sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc 271 | url: "https://pub.dev" 272 | source: hosted 273 | version: "14.2.4" 274 | xdg_directories: 275 | dependency: transitive 276 | description: 277 | name: xdg_directories 278 | sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d 279 | url: "https://pub.dev" 280 | source: hosted 281 | version: "1.0.4" 282 | xml: 283 | dependency: transitive 284 | description: 285 | name: xml 286 | sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 287 | url: "https://pub.dev" 288 | source: hosted 289 | version: "6.5.0" 290 | sdks: 291 | dart: ">=3.3.0 <4.0.0" 292 | flutter: ">=3.18.0-18.0.pre.54" 293 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_background_example 2 | description: An example app that demonstrates how to use the flutter_background plugin. 3 | 4 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 5 | 6 | environment: 7 | sdk: ">=2.12.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | flutter_local_notifications: ^17.2.2 13 | bubble: ^1.2.1 14 | 15 | flutter_background: 16 | # When depending on this package from a real application you should use: 17 | # flutter_background: ^x.y.z 18 | # See https://dart.dev/tools/pub/dependencies#version-constraints 19 | # The example app is bundled with the plugin so we use a path dependency on 20 | # the parent directory to use the current plugin's version. 21 | path: ../ 22 | 23 | dev_dependencies: 24 | flutter_test: 25 | sdk: flutter 26 | 27 | flutter: 28 | uses-material-design: true -------------------------------------------------------------------------------- /example/server/server.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | import 'dart:async'; 3 | import 'dart:io'; 4 | 5 | import 'dart:typed_data'; 6 | 7 | Future startServer() async { 8 | final server = await ServerSocket.bind('0.0.0.0', 6666); 9 | print('TCP server started at ${server.address}:${server.port}.'); 10 | 11 | try { 12 | server.listen((Socket socket) { 13 | print( 14 | 'New TCP client ${socket.address.address}:${socket.port} connected.'); 15 | var totalSeconds = 0; 16 | final timer = Timer.periodic(const Duration(seconds: 10), (timer) { 17 | totalSeconds += 10; 18 | 19 | final hours = totalSeconds ~/ 3600; 20 | final minutes = (totalSeconds ~/ 60) % 60; 21 | final seconds = totalSeconds % 60; 22 | final message = 23 | '${DateTime.now().toString()}: ${hours}h ${minutes}m ${seconds}s'; 24 | 25 | socket.add(message.codeUnits); 26 | print('Sending message $message'); 27 | }); 28 | socket.handleError((err, stacktrace) { 29 | print('Connection closed with error $err\nStacktrace: $stacktrace'); 30 | timer.cancel(); 31 | }).listen((Uint8List data) { 32 | print('Incoming message from client: ${String.fromCharCodes(data)}'); 33 | }); 34 | }); 35 | } on SocketException catch (ex) { 36 | print(ex.message); 37 | } 38 | } 39 | 40 | void main() { 41 | startServer(); 42 | } 43 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | void main() {} 2 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | example 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /flutter_background.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /images/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/images/notification.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianAssmann/flutter_background/528bf438e41aec9b9642d9e3e32cb598c0a1ca51/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/FlutterBackgroundPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterBackgroundPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/FlutterBackgroundPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterBackgroundPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "flutter_background-Swift.h" 9 | #endif 10 | 11 | @implementation FlutterBackgroundPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftFlutterBackgroundPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterBackgroundPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | public class SwiftFlutterBackgroundPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "flutter_background", binaryMessenger: registrar.messenger()) 7 | let instance = SwiftFlutterBackgroundPlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | result("iOS " + UIDevice.current.systemVersion) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/flutter_background.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_background.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_background' 7 | s.version = '0.0.1' 8 | s.summary = 'A plugin to keep flutter apps running in the background.' 9 | s.description = <<-DESC 10 | A plugin to keep flutter apps running in the background. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '8.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /lib/flutter_background.dart: -------------------------------------------------------------------------------- 1 | export 'src/android_config.dart'; 2 | export 'src/flutter_background.dart'; 3 | -------------------------------------------------------------------------------- /lib/src/android_config.dart: -------------------------------------------------------------------------------- 1 | /// Represents the importance of an android notification as described 2 | /// under https://developer.android.com/training/notify-user/channels#importance. 3 | enum AndroidNotificationImportance { 4 | // Low and min importance levels apparantly are not supported, see 5 | // https://github.com/JulianAssmann/flutter_background/issues/37 for more. 6 | 7 | // Min, 8 | // Low, 9 | normal, 10 | high, 11 | max, 12 | } 13 | 14 | // Represents the information required to get an Android resource. 15 | // See https://developer.android.com/reference/android/content/res/Resources for reference. 16 | class AndroidResource { 17 | // The name of the desired resource. 18 | final String name; 19 | 20 | // Optional default resource type to find, if "type/" is not included in the name. Can be null to require an explicit type. 21 | final String defType; 22 | 23 | const AndroidResource({required this.name, this.defType = 'drawable'}); 24 | } 25 | 26 | /// Android configuration for the [FlutterBackground] plugin. 27 | class FlutterBackgroundAndroidConfig { 28 | /// The importance of the notification used for the foreground service. 29 | final AndroidNotificationImportance notificationImportance; 30 | 31 | /// The title used for the foreground service notification. 32 | final String notificationTitle; 33 | 34 | /// The body used for the foreground service notification. 35 | final String notificationText; 36 | 37 | /// The resource name of the icon to be used for the foreground notification. 38 | final AndroidResource notificationIcon; 39 | 40 | /// When enabled, a WifiLock is acquired when background execution is started. 41 | /// This allows the application to keep the Wi-Fi radio awake, even when the 42 | /// user has not used the device in a while (e.g. for background network 43 | /// communications). 44 | final bool enableWifiLock; 45 | 46 | /// Show or hide notification badge on the app icon when the foreground 47 | /// notification is shown (you have to reinstall the app for the change to 48 | /// take effect). 49 | final bool showBadge; 50 | 51 | /// When enabled, request permission to disable battery optimizations. 52 | /// This is enabled by default, and should only be disabled on platforms that 53 | /// do not support it (ex: Wear OS). 54 | final bool shouldRequestBatteryOptimizationsOff; 55 | 56 | /// Creates an Android specific configuration for the [FlutterBackground] plugin. 57 | /// 58 | /// [notificationTitle] is the title used for the foreground service notification. 59 | /// [notificationText] is the body used for the foreground service notification. 60 | /// [notificationImportance] is the importance of the foreground service notification. 61 | /// [notificationIcon] must be a drawable resource. 62 | /// E. g. if the icon with name "background_icon" is in the "drawable" resource folder, 63 | /// it should be of value `AndroidResource(name: 'background_icon', defType: 'drawable'). 64 | /// [enableWifiLock] indicates wether or not a WifiLock is acquired, when the 65 | /// background execution is started. This allows the application to keep the 66 | /// Wi-Fi radio awake, even when the user has not used the device in a while. 67 | /// [showBadge] indicates whether the notification badge should be shown/incremented 68 | /// or not. 69 | /// [shouldRequestBatteryOptimizationsOff] indicates whether or not to request 70 | /// permission to disable battery optimizations. This is enabled by default, and 71 | /// should only be disabled on platforms that do not support it (ex: Wear OS). 72 | const FlutterBackgroundAndroidConfig({ 73 | this.notificationTitle = 'Notification title', 74 | this.notificationText = 'Notification text', 75 | this.notificationImportance = AndroidNotificationImportance.normal, 76 | this.notificationIcon = 77 | const AndroidResource(name: 'ic_launcher', defType: 'mipmap'), 78 | this.enableWifiLock = true, 79 | this.showBadge = true, 80 | this.shouldRequestBatteryOptimizationsOff = true, 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/flutter_background.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'android_config.dart'; 5 | 6 | class FlutterBackground { 7 | static const MethodChannel _channel = MethodChannel('flutter_background'); 8 | 9 | static bool _isInitialized = false; 10 | static bool _isBackgroundExecutionEnabled = false; 11 | 12 | /// Initializes the plugin. 13 | /// May request the necessary permissions from the user in order to run in the background. 14 | /// 15 | /// Does nothing and returns true if the permissions are already granted. 16 | /// Returns true, if the user grants the permissions, otherwise false. 17 | /// May throw a [PlatformException]. 18 | static Future initialize( 19 | {FlutterBackgroundAndroidConfig androidConfig = 20 | const FlutterBackgroundAndroidConfig()}) async { 21 | _isInitialized = await _channel.invokeMethod('initialize', { 22 | 'android.notificationTitle': androidConfig.notificationTitle, 23 | 'android.notificationText': androidConfig.notificationText, 24 | 'android.notificationImportance': _androidNotificationImportanceToInt( 25 | androidConfig.notificationImportance), 26 | 'android.notificationIconName': androidConfig.notificationIcon.name, 27 | 'android.notificationIconDefType': 28 | androidConfig.notificationIcon.defType, 29 | 'android.enableWifiLock': androidConfig.enableWifiLock, 30 | 'android.showBadge': androidConfig.showBadge, 31 | 'android.shouldRequestBatteryOptimizationsOff': 32 | androidConfig.shouldRequestBatteryOptimizationsOff, 33 | }) == 34 | true; 35 | return _isInitialized; 36 | } 37 | 38 | /// Indicates whether or not the user has given the necessary permissions in order to run in the background. 39 | /// 40 | /// Returns true, if the user has granted the permission, otherwise false. 41 | /// May throw a [PlatformException]. 42 | static Future get hasPermissions async { 43 | return await _channel.invokeMethod('hasPermissions') == true; 44 | } 45 | 46 | /// Enables the execution of the flutter app in the background. 47 | /// You must to call [FlutterBackground.initialize()] before calling this function. 48 | /// 49 | /// Returns true if successful, otherwise false. 50 | /// Throws an [Exception] if the plugin is not initialized by calling [FlutterBackground.initialize()] first. 51 | /// May throw a [PlatformException]. 52 | static Future enableBackgroundExecution() async { 53 | if (_isInitialized) { 54 | final success = 55 | await _channel.invokeMethod('enableBackgroundExecution'); 56 | _isBackgroundExecutionEnabled = true; 57 | return success == true; 58 | } else { 59 | throw Exception( 60 | 'FlutterBackground plugin must be initialized before calling enableBackgroundExecution()'); 61 | } 62 | } 63 | 64 | /// Disables the execution of the flutter app in the background. 65 | /// You must to call [FlutterBackground.initialize()] before calling this function. 66 | /// 67 | /// Returns true if successful, otherwise false. 68 | /// Throws an [Exception] if the plugin is not initialized by calling [FlutterBackground.initialize()] first. 69 | /// May throw a [PlatformException]. 70 | static Future disableBackgroundExecution() async { 71 | if (_isInitialized) { 72 | final success = 73 | await _channel.invokeMethod('disableBackgroundExecution'); 74 | _isBackgroundExecutionEnabled = false; 75 | return success == true; 76 | } else { 77 | throw Exception( 78 | 'FlutterBackground plugin must be initialized before calling disableBackgroundExecution()'); 79 | } 80 | } 81 | 82 | /// Indicates whether background execution is currently enabled. 83 | static bool get isBackgroundExecutionEnabled => _isBackgroundExecutionEnabled; 84 | 85 | static int _androidNotificationImportanceToInt( 86 | AndroidNotificationImportance importance) { 87 | switch (importance) { 88 | // Low and min importance levels apparantly are not supported, see 89 | // https://github.com/JulianAssmann/flutter_background/issues/37 for more. 90 | 91 | // case AndroidNotificationImportance.Low: 92 | // return -1; 93 | // case AndroidNotificationImportance.Min: 94 | // return -2; 95 | case AndroidNotificationImportance.high: 96 | return 1; 97 | case AndroidNotificationImportance.max: 98 | return 2; 99 | case AndroidNotificationImportance.normal: 100 | default: 101 | return 0; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.1" 52 | flutter: 53 | dependency: "direct main" 54 | description: flutter 55 | source: sdk 56 | version: "0.0.0" 57 | flutter_lints: 58 | dependency: "direct dev" 59 | description: 60 | name: flutter_lints 61 | sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" 62 | url: "https://pub.dev" 63 | source: hosted 64 | version: "4.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | leak_tracker: 71 | dependency: transitive 72 | description: 73 | name: leak_tracker 74 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "10.0.5" 78 | leak_tracker_flutter_testing: 79 | dependency: transitive 80 | description: 81 | name: leak_tracker_flutter_testing 82 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "3.0.5" 86 | leak_tracker_testing: 87 | dependency: transitive 88 | description: 89 | name: leak_tracker_testing 90 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "3.0.1" 94 | lints: 95 | dependency: transitive 96 | description: 97 | name: lints 98 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "4.0.0" 102 | matcher: 103 | dependency: transitive 104 | description: 105 | name: matcher 106 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "0.12.16+1" 110 | material_color_utilities: 111 | dependency: transitive 112 | description: 113 | name: material_color_utilities 114 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "0.11.1" 118 | meta: 119 | dependency: transitive 120 | description: 121 | name: meta 122 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "1.15.0" 126 | path: 127 | dependency: transitive 128 | description: 129 | name: path 130 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "1.9.0" 134 | plugin_platform_interface: 135 | dependency: "direct main" 136 | description: 137 | name: plugin_platform_interface 138 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "2.1.8" 142 | sky_engine: 143 | dependency: transitive 144 | description: flutter 145 | source: sdk 146 | version: "0.0.99" 147 | source_span: 148 | dependency: transitive 149 | description: 150 | name: source_span 151 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "1.10.0" 155 | stack_trace: 156 | dependency: transitive 157 | description: 158 | name: stack_trace 159 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "1.11.1" 163 | stream_channel: 164 | dependency: transitive 165 | description: 166 | name: stream_channel 167 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "2.1.2" 171 | string_scanner: 172 | dependency: transitive 173 | description: 174 | name: string_scanner 175 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "1.2.0" 179 | term_glyph: 180 | dependency: transitive 181 | description: 182 | name: term_glyph 183 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "1.2.1" 187 | test_api: 188 | dependency: transitive 189 | description: 190 | name: test_api 191 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "0.7.2" 195 | vector_math: 196 | dependency: transitive 197 | description: 198 | name: vector_math 199 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "2.1.4" 203 | vm_service: 204 | dependency: transitive 205 | description: 206 | name: vm_service 207 | sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "14.2.4" 211 | sdks: 212 | dart: ">=3.3.0 <4.0.0" 213 | flutter: ">=3.18.0-18.0.pre.54" 214 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_background 2 | description: Run apps in the background using foreground services on Android. Ideal for applications that require continuous operation, such as background data synchronization or messaging. 3 | version: 1.3.0+1 4 | repository: https://github.com/JulianAssmann/flutter_background 5 | homepage: https://julianassmann.de/ 6 | 7 | environment: 8 | sdk: ">=3.4.0 <4.0.0" 9 | flutter: ">=3.16.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | plugin_platform_interface: ^2.1.8 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | flutter_lints: ^4.0.0 20 | 21 | flutter: 22 | plugin: 23 | platforms: 24 | android: 25 | package: de.julianassmann.flutter_background 26 | pluginClass: FlutterBackgroundPlugin 27 | -------------------------------------------------------------------------------- /test/flutter_background_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | TestWidgetsFlutterBinding.ensureInitialized(); 5 | } 6 | --------------------------------------------------------------------------------