├── .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 | [](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 | 
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/android/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
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 |
--------------------------------------------------------------------------------