parent
2d63a24fb1
commit
63a2277119
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,236 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart Packages" type="DartPackagesLibraryType">
|
||||
<properties>
|
||||
<option name="packageNameToDirsMap">
|
||||
<entry key="async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="boolean_selector">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="characters">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="charcode">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="clock">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="collection">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="cupertino_icons">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="datang">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="english_words">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/english_words-4.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="fake_async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/packages/flutter/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_lints">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/packages/flutter_test/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="lints">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="matcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="material_color_utilities">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="meta">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="platform">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/platform-3.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="sky_engine">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_span">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stream_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="string_scanner">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="telephony">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/telephony-0.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="term_glyph">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_api">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.9/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vector_math">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</option>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/english_words-4.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/platform-3.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.2/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/telephony-0.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.9/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/packages/flutter/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/packages/flutter_test/lib" />
|
||||
<root url="file://$USER_HOME$/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,27 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart SDK">
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/async" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/cli" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/collection" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/convert" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/core" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/developer" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/ffi" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/html" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/indexed_db" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/io" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/isolate" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/js" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/js_util" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/math" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/mirrors" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/svg" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/typed_data" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/web_audio" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/dart-sdk/lib/web_gl" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,7 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Flutter Plugins" type="FlutterPluginsLibraryType">
|
||||
<CLASSES />
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/flutter_background_service_android.iml" filepath="$PROJECT_DIR$/.idea/flutter_background_service_android.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,180 @@
|
||||
## 2.0.3
|
||||
|
||||
- **FIX**: wakelock not released. ([e427f3b7](https://github.com/ekasetiawans/flutter_background_service/commit/e427f3b70138ec26f9671c2617f9061f25eade6f))
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- **FIX**: autoStartOnBootMode #160. ([16a785a3](https://github.com/ekasetiawans/flutter_background_service/commit/16a785a3cbcb4226321ddddf681b6554196fa4db))
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- **FIX**: release wakelock. ([c0830250](https://github.com/ekasetiawans/flutter_background_service/commit/c0830250b90a1ba6e2543a1bb25a13fba59a56b7))
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
|
||||
|
||||
## 2.0.0-dev.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **BREAKING** **FEAT**: implement new concept. ([c8ce9c0b](https://github.com/ekasetiawans/flutter_background_service/commit/c8ce9c0bab82137dea031af124b84510286661f7))
|
||||
|
||||
## 1.0.2
|
||||
|
||||
- **DOCS**: readme link. ([1479b91c](https://github.com/ekasetiawans/flutter_background_service/commit/1479b91cd80d637335de1314a528bcf51ebb7c0f))
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- **DOCS**: update README. ([fbf5e0ab](https://github.com/ekasetiawans/flutter_background_service/commit/fbf5e0abeeb9296ba32361b8af0a298ee9e71527))
|
||||
|
||||
## 0.0.2
|
||||
|
||||
- **FEAT**: migrate to plugin platform interface. ([70e08ff0](https://github.com/ekasetiawans/flutter_background_service/commit/70e08ff03232c31946cc8eb7896f69c830f23322))
|
||||
|
||||
## 0.0.1+3
|
||||
|
||||
- **FIX**: errors. ([13a6f841](https://github.com/ekasetiawans/flutter_background_service/commit/13a6f841f5d677ceb0010e8ba1bf9d7af53adbcf))
|
||||
|
||||
## 0.0.1+2
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.0.1+1
|
||||
|
||||
- **REFACTOR**: initialize melos.
|
||||
|
||||
## 0.2.6
|
||||
* FIX: (Android) flutter initialization
|
||||
## 0.2.5
|
||||
* FIX: (iOS) using other plugins
|
||||
## 0.2.4
|
||||
* FIX: (Android) run service background when charger not connected and screen lock (#92)
|
||||
## 0.2.3
|
||||
* ADDED: Using `BGTaskScheduler` on iOS 13. See readme for configuration.
|
||||
## 0.2.2
|
||||
* ADDED: `autoStart` to `IosConfiguration`
|
||||
## 0.2.1
|
||||
* UPDATE README
|
||||
* UPDATE: Flutter Version Constraint
|
||||
## 0.2.0+1
|
||||
* UPDATE README
|
||||
|
||||
## 0.2.0
|
||||
* [BREAKING]: FlutterBackgroundService.initialize renamed to FlutterBackgroundService.configure
|
||||
* [BREAKING]: use FlutterBackgroundService.start to start or restart after you call stopService.
|
||||
* [ADDED]: IOS Background fetch is now supported you have to enable background fetch from xcode.
|
||||
## 0.1.7
|
||||
|
||||
* Fix : cannot start service on android 12
|
||||
* Fix : not started on boot completed
|
||||
## 0.1.6
|
||||
|
||||
* Android 12 Compatibility Changes
|
||||
## 0.1.5
|
||||
|
||||
* Rollback foreground notification importance
|
||||
## 0.1.4
|
||||
|
||||
* fixes UnsatisfiedLinkError when running as foreground service with autostart #32
|
||||
## 0.1.3
|
||||
|
||||
* Fix notification not showing on android 7 and prior (Issue #26)
|
||||
## 0.1.2
|
||||
|
||||
* Open app from notification (Issue #30)
|
||||
## 0.1.1
|
||||
|
||||
* Fix #29 (DartVM not terminated when service stop)
|
||||
|
||||
## 0.1.0
|
||||
|
||||
* Bump flutter 2
|
||||
|
||||
## 0.1.0-nullsafety.2
|
||||
|
||||
* Fix #23
|
||||
|
||||
## 0.1.0-nullsafety.1
|
||||
|
||||
* Added isServiceRunning on iOS (issue #19)
|
||||
|
||||
## 0.1.0-nullsafety.0
|
||||
|
||||
* Added support to nullsafety
|
||||
|
||||
## 0.0.1+18
|
||||
|
||||
* Added stopService Method(Currently Works on Android Only).
|
||||
|
||||
## 0.0.1+17
|
||||
|
||||
* Add preference autoStart on Boot, default is true.
|
||||
|
||||
## 0.0.1+16
|
||||
|
||||
* Set Foreground Mode to false will remove notification. BugFix #4.
|
||||
|
||||
## 0.0.1+15
|
||||
|
||||
* Add ability to change Background or Foreground mode (Android Only)
|
||||
|
||||
## 0.0.1+14
|
||||
|
||||
* Bugfix BootReceiver
|
||||
|
||||
## 0.0.1+13
|
||||
|
||||
* Update example for iOS support.
|
||||
|
||||
## 0.0.1+12
|
||||
|
||||
* Start service immediately after initialize
|
||||
|
||||
## 0.0.1+11
|
||||
|
||||
* iOS
|
||||
|
||||
## 0.0.1+10
|
||||
|
||||
* bug fix
|
||||
|
||||
## 0.0.1+9
|
||||
|
||||
* bug fix
|
||||
|
||||
## 0.0.1+8
|
||||
|
||||
* bug fix
|
||||
|
||||
## 0.0.1+7
|
||||
|
||||
* Add ability to send data from UI to Service
|
||||
|
||||
## 0.0.1+6
|
||||
|
||||
* Improve stability
|
||||
|
||||
## 0.0.1+5
|
||||
|
||||
* Add ability to send data from service to UI
|
||||
|
||||
## 0.0.1+4
|
||||
|
||||
* Update README
|
||||
|
||||
## 0.0.1+3
|
||||
|
||||
* Add ability to change notification info (Android foreground service)
|
||||
|
||||
## 0.0.1+2
|
||||
|
||||
* Fix android missing plugin implementation
|
||||
|
||||
## 0.0.1+1
|
||||
|
||||
* Fix android build
|
||||
|
||||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
@ -0,0 +1,25 @@
|
||||
Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,37 @@
|
||||
group 'id.flutter.flutter_background_service'
|
||||
version '1.0'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
}
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
@ -0,0 +1,6 @@
|
||||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
@ -0,0 +1 @@
|
||||
rootProject.name = 'flutter_background_service'
|
@ -0,0 +1,32 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="id.flutter.flutter_background_service">
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:name=".BackgroundService"
|
||||
/>
|
||||
|
||||
<receiver
|
||||
android:name=".WatchdogReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
/>
|
||||
|
||||
<receiver android:name=".BootReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,327 @@
|
||||
package id.flutter.flutter_background_service;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.AlarmManagerCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.lang.UnsatisfiedLinkError;
|
||||
|
||||
import io.flutter.FlutterInjector;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.loader.FlutterLoader;
|
||||
import io.flutter.plugin.common.JSONMethodCodec;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.view.FlutterCallbackInformation;
|
||||
|
||||
public class BackgroundService extends Service implements MethodChannel.MethodCallHandler {
|
||||
private static final String TAG = "BackgroundService";
|
||||
private FlutterEngine backgroundEngine;
|
||||
private MethodChannel methodChannel;
|
||||
private DartExecutor.DartCallback dartCallback;
|
||||
private boolean isManuallyStopped = false;
|
||||
|
||||
String notificationTitle = "短信帮手正在后台运行";
|
||||
String notificationContent = "Running";
|
||||
private static final String LOCK_NAME = BackgroundService.class.getName()
|
||||
+ ".Lock";
|
||||
public static volatile WakeLock lockStatic = null; // notice static
|
||||
|
||||
synchronized public static PowerManager.WakeLock getLock(Context context) {
|
||||
if (lockStatic == null) {
|
||||
PowerManager mgr = (PowerManager) context
|
||||
.getSystemService(Context.POWER_SERVICE);
|
||||
lockStatic = mgr.newWakeLock(PowerManager.FULL_WAKE_LOCK,
|
||||
LOCK_NAME);
|
||||
lockStatic.setReferenceCounted(true);
|
||||
}
|
||||
return (lockStatic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void enqueue(Context context) {
|
||||
Intent intent = new Intent(context, WatchdogReceiver.class);
|
||||
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
flags |= PendingIntent.FLAG_MUTABLE;
|
||||
}
|
||||
|
||||
PendingIntent pIntent = PendingIntent.getBroadcast(context, 111, intent, flags);
|
||||
AlarmManagerCompat.setAndAllowWhileIdle(manager, AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, pIntent);
|
||||
}
|
||||
|
||||
public void setAutoStartOnBootMode(boolean value) {
|
||||
SharedPreferences pref = getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
pref.edit().putBoolean("auto_start_on_boot", value).apply();
|
||||
}
|
||||
|
||||
public static boolean isAutoStartOnBootMode(Context context) {
|
||||
SharedPreferences pref = context.getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
return pref.getBoolean("auto_start_on_boot", true);
|
||||
}
|
||||
|
||||
public void setForegroundServiceMode(boolean value) {
|
||||
SharedPreferences pref = getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
pref.edit().putBoolean("is_foreground", value).apply();
|
||||
}
|
||||
|
||||
public static boolean isForegroundService(Context context) {
|
||||
SharedPreferences pref = context.getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
return pref.getBoolean("is_foreground", true);
|
||||
}
|
||||
|
||||
public void setManuallyStopped(boolean value) {
|
||||
SharedPreferences pref = getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
pref.edit().putBoolean("is_manually_stopped", value).apply();
|
||||
}
|
||||
|
||||
public static boolean isManuallyStopped(Context context) {
|
||||
SharedPreferences pref = context.getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
return pref.getBoolean("is_manually_stopped", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
createNotificationChannel();
|
||||
notificationContent = "点击即可查看更多选项。";
|
||||
updateNotificationInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (!isManuallyStopped) {
|
||||
enqueue(this);
|
||||
} else {
|
||||
setManuallyStopped(true);
|
||||
}
|
||||
stopForeground(true);
|
||||
isRunning.set(false);
|
||||
|
||||
if (backgroundEngine != null) {
|
||||
backgroundEngine.getServiceControlSurface().detachFromService();
|
||||
backgroundEngine.destroy();
|
||||
backgroundEngine = null;
|
||||
}
|
||||
|
||||
methodChannel = null;
|
||||
dartCallback = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CharSequence name = "Background Service";
|
||||
String description = "Executing process in background";
|
||||
|
||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||
NotificationChannel channel = new NotificationChannel("FOREGROUND_DEFAULT", name, importance);
|
||||
channel.setDescription(description);
|
||||
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateNotificationInfo() {
|
||||
if (isForegroundService(this)) {
|
||||
|
||||
String packageName = getApplicationContext().getPackageName();
|
||||
Intent i = getPackageManager().getLaunchIntentForPackage(packageName);
|
||||
|
||||
int flags = PendingIntent.FLAG_CANCEL_CURRENT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
flags |= PendingIntent.FLAG_MUTABLE;
|
||||
}
|
||||
|
||||
PendingIntent pi = PendingIntent.getActivity(BackgroundService.this, 99778, i, flags);
|
||||
|
||||
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "FOREGROUND_DEFAULT")
|
||||
.setSmallIcon(R.drawable.ic_bg_service_small)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(true)
|
||||
.setContentTitle(notificationTitle)
|
||||
.setContentText(notificationContent)
|
||||
.setContentIntent(pi);
|
||||
|
||||
startForeground(99778, mBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
setManuallyStopped(false);
|
||||
enqueue(this);
|
||||
runService();
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
|
||||
private void runService() {
|
||||
try {
|
||||
Log.d(TAG, "runService");
|
||||
if (isRunning.get() || (backgroundEngine != null && !backgroundEngine.getDartExecutor().isExecutingDart()))
|
||||
return;
|
||||
|
||||
if (lockStatic == null){
|
||||
getLock(getApplicationContext()).acquire(10*60*1000L /*10 minutes*/);
|
||||
}
|
||||
|
||||
updateNotificationInfo();
|
||||
|
||||
SharedPreferences pref = getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
long entrypointHandle = pref.getLong("entrypoint_handle", 0);
|
||||
|
||||
FlutterLoader flutterLoader = FlutterInjector.instance().flutterLoader();
|
||||
// initialize flutter if it's not initialized yet
|
||||
if (!flutterLoader.initialized()) {
|
||||
flutterLoader.startInitialization(getApplicationContext());
|
||||
}
|
||||
|
||||
flutterLoader.ensureInitializationComplete(getApplicationContext(), null);
|
||||
FlutterCallbackInformation callback = FlutterCallbackInformation.lookupCallbackInformation(entrypointHandle);
|
||||
if (callback == null) {
|
||||
Log.e(TAG, "callback handle not found");
|
||||
return;
|
||||
}
|
||||
|
||||
isRunning.set(true);
|
||||
backgroundEngine = new FlutterEngine(this);
|
||||
backgroundEngine.getServiceControlSurface().attachToService(BackgroundService.this, null, isForegroundService(this));
|
||||
|
||||
methodChannel = new MethodChannel(backgroundEngine.getDartExecutor().getBinaryMessenger(), "id.flutter/background_service_android_bg", JSONMethodCodec.INSTANCE);
|
||||
methodChannel.setMethodCallHandler(this);
|
||||
|
||||
dartCallback = new DartExecutor.DartCallback(getAssets(), flutterLoader.findAppBundlePath(), callback);
|
||||
backgroundEngine.getDartExecutor().executeDartCallback(dartCallback);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
notificationContent = "Error " + e.getMessage();
|
||||
updateNotificationInfo();
|
||||
|
||||
Log.w(TAG, "UnsatisfiedLinkError: After a reboot this may happen for a short period and it is ok to ignore then!" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveData(JSONObject data) {
|
||||
if (methodChannel != null) {
|
||||
try {
|
||||
methodChannel.invokeMethod("onReceiveData", data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
|
||||
String method = call.method;
|
||||
|
||||
try {
|
||||
if (method.equalsIgnoreCase("getHandler")) {
|
||||
SharedPreferences pref = getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
long backgroundHandle = pref.getLong("background_handle", 0);
|
||||
result.success(backgroundHandle);
|
||||
|
||||
if (lockStatic != null) {
|
||||
lockStatic.release();
|
||||
lockStatic = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("setNotificationInfo")) {
|
||||
JSONObject arg = (JSONObject) call.arguments;
|
||||
if (arg.has("title")) {
|
||||
notificationTitle = arg.getString("title");
|
||||
notificationContent = arg.getString("content");
|
||||
updateNotificationInfo();
|
||||
result.success(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("setAutoStartOnBootMode")) {
|
||||
JSONObject arg = (JSONObject) call.arguments;
|
||||
boolean value = arg.getBoolean("value");
|
||||
setAutoStartOnBootMode(value);
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("setForegroundMode")) {
|
||||
JSONObject arg = (JSONObject) call.arguments;
|
||||
boolean value = arg.getBoolean("value");
|
||||
setForegroundServiceMode(value);
|
||||
if (value) {
|
||||
updateNotificationInfo();
|
||||
} else {
|
||||
stopForeground(true);
|
||||
}
|
||||
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("stopService")) {
|
||||
isManuallyStopped = true;
|
||||
Intent intent = new Intent(this, WatchdogReceiver.class);
|
||||
|
||||
int flags = PendingIntent.FLAG_CANCEL_CURRENT;
|
||||
if (SDK_INT >= Build.VERSION_CODES.S) {
|
||||
flags |= PendingIntent.FLAG_MUTABLE;
|
||||
}
|
||||
|
||||
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 111, intent, flags);
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
||||
alarmManager.cancel(pi);
|
||||
stopSelf();
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("sendData")) {
|
||||
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
|
||||
Intent intent = new Intent("id.flutter/background_service");
|
||||
intent.putExtra("data", call.arguments.toString());
|
||||
manager.sendBroadcast(intent);
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
result.notImplemented();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package id.flutter.flutter_background_service;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SharedPreferences pref = context.getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
boolean autoStart = pref.getBoolean("auto_start_on_boot",true);
|
||||
if(autoStart) {
|
||||
if (BackgroundService.lockStatic == null){
|
||||
BackgroundService.getLock(context).acquire(10*60*1000L /*10 minutes*/);
|
||||
}
|
||||
|
||||
if (BackgroundService.isForegroundService(context)) {
|
||||
ContextCompat.startForegroundService(context, new Intent(context, BackgroundService.class));
|
||||
} else {
|
||||
context.startService(new Intent(context, BackgroundService.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package id.flutter.flutter_background_service;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.service.ServiceAware;
|
||||
import io.flutter.embedding.engine.plugins.service.ServicePluginBinding;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||
import io.flutter.plugin.common.JSONMethodCodec;
|
||||
|
||||
/** FlutterBackgroundServicePlugin */
|
||||
public class FlutterBackgroundServicePlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, ServiceAware {
|
||||
private static final String TAG = "BackgroundServicePlugin";
|
||||
private static final List<FlutterBackgroundServicePlugin> _instances = new ArrayList<>();
|
||||
|
||||
public FlutterBackgroundServicePlugin() {
|
||||
_instances.add(this);
|
||||
}
|
||||
|
||||
private MethodChannel channel;
|
||||
private Context context;
|
||||
private BackgroundService service;
|
||||
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
|
||||
this.context = flutterPluginBinding.getApplicationContext();
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this.context);
|
||||
localBroadcastManager.registerReceiver(this, new IntentFilter("id.flutter/background_service"));
|
||||
|
||||
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "id.flutter/background_service_android", JSONMethodCodec.INSTANCE);
|
||||
channel.setMethodCallHandler(this);
|
||||
}
|
||||
|
||||
public static void registerWith(Registrar registrar) {
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(registrar.context());
|
||||
final FlutterBackgroundServicePlugin plugin = new FlutterBackgroundServicePlugin();
|
||||
localBroadcastManager.registerReceiver(plugin, new IntentFilter("id.flutter/background_service"));
|
||||
|
||||
final MethodChannel channel = new MethodChannel(registrar.messenger(), "id.flutter/background_service_android", JSONMethodCodec.INSTANCE);
|
||||
channel.setMethodCallHandler(plugin);
|
||||
plugin.channel = channel;
|
||||
}
|
||||
|
||||
private static void configure(Context context, long entrypointHandle, long backgroundHandle, boolean isForeground, boolean autoStartOnBoot) {
|
||||
SharedPreferences pref = context.getSharedPreferences("id.flutter.background_service", MODE_PRIVATE);
|
||||
pref.edit()
|
||||
.putLong("entrypoint_handle", entrypointHandle)
|
||||
.putLong("background_handle", backgroundHandle)
|
||||
.putBoolean("is_foreground", isForeground)
|
||||
.putBoolean("auto_start_on_boot", autoStartOnBoot)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
BackgroundService.enqueue(context);
|
||||
boolean isForeground = BackgroundService.isForegroundService(context);
|
||||
Intent intent = new Intent(context, BackgroundService.class);
|
||||
if (isForeground) {
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
} else {
|
||||
context.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
|
||||
String method = call.method;
|
||||
JSONObject arg = (JSONObject) call.arguments;
|
||||
|
||||
try {
|
||||
if ("configure".equals(method)) {
|
||||
long entrypointHandle = arg.getLong("entrypoint_handle");
|
||||
long backgroundHandle = arg.getLong("background_handle");
|
||||
boolean isForeground = arg.getBoolean("is_foreground_mode");
|
||||
boolean autoStartOnBoot = arg.getBoolean("auto_start_on_boot");
|
||||
|
||||
configure(context, entrypointHandle, backgroundHandle, isForeground, autoStartOnBoot);
|
||||
if (autoStartOnBoot) {
|
||||
start();
|
||||
}
|
||||
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("start".equals(method)) {
|
||||
start();
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("sendData")) {
|
||||
for (FlutterBackgroundServicePlugin plugin : _instances) {
|
||||
if (plugin.service != null) {
|
||||
plugin.service.receiveData((JSONObject) call.arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.equalsIgnoreCase("isServiceRunning")) {
|
||||
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (BackgroundService.class.getName().equals(service.service.getClassName())) {
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result.success(false);
|
||||
return;
|
||||
}
|
||||
|
||||
result.notImplemented();
|
||||
} catch (Exception e) {
|
||||
result.error("100", "Failed read arguments", null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||
channel.setMethodCallHandler(null);
|
||||
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this.context);
|
||||
localBroadcastManager.unregisterReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction() == null) return;
|
||||
|
||||
if (intent.getAction().equalsIgnoreCase("id.flutter/background_service")) {
|
||||
String data = intent.getStringExtra("data");
|
||||
try {
|
||||
JSONObject jData = new JSONObject(data);
|
||||
if (channel != null) {
|
||||
channel.invokeMethod("onReceiveData", jData);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToService(@NonNull ServicePluginBinding binding) {
|
||||
Log.d(TAG, "onAttachedToService");
|
||||
|
||||
this.service = (BackgroundService) binding.getService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromService() {
|
||||
this.service = null;
|
||||
Log.d(TAG, "onDetachedFromService");
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package id.flutter.flutter_background_service;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
public class WatchdogReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if(!BackgroundService.isManuallyStopped(context)) {
|
||||
if (BackgroundService.isForegroundService(context)) {
|
||||
ContextCompat.startForegroundService(context, new Intent(context, BackgroundService.class));
|
||||
} else {
|
||||
context.startService(new Intent(context, BackgroundService.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="1.38"
|
||||
android:scaleY="1.38"
|
||||
android:translateX="-4.56"
|
||||
android:translateY="-4.56">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6.05,8.05c-2.73,2.73 -2.73,7.15 -0.02,9.88c1.47,-3.4 4.09,-6.24 7.36,-7.93c-2.77,2.34 -4.71,5.61 -5.39,9.32c2.6,1.23 5.8,0.78 7.95,-1.37C19.43,14.47 20,4 20,4S9.53,4.57 6.05,8.05z"/>
|
||||
</group>
|
||||
</vector>
|
After Width: | Height: | Size: 416 B |
After Width: | Height: | Size: 304 B |
After Width: | Height: | Size: 505 B |
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/build" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,186 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_background_service_platform_interface/flutter_background_service_platform_interface.dart';
|
||||
|
||||
Future<void> _entrypoint() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final service = AndroidServiceInstance._();
|
||||
final int handle = await service._getHandler();
|
||||
final callbackHandle = CallbackHandle.fromRawHandle(handle);
|
||||
final onStart = PluginUtilities.getCallbackFromHandle(callbackHandle);
|
||||
if (onStart != null) {
|
||||
onStart(service);
|
||||
}
|
||||
}
|
||||
|
||||
class FlutterBackgroundServiceAndroid extends FlutterBackgroundServicePlatform {
|
||||
/// Registers this class as the default instance of [FlutterBackgroundServicePlatform].
|
||||
static void registerWith() {
|
||||
FlutterBackgroundServicePlatform.instance =
|
||||
FlutterBackgroundServiceAndroid();
|
||||
}
|
||||
|
||||
static const MethodChannel _channel = const MethodChannel(
|
||||
'id.flutter/background_service_android',
|
||||
JSONMethodCodec(),
|
||||
);
|
||||
|
||||
Future<dynamic> _handle(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case "onReceiveData":
|
||||
_controller.sink.add(call.arguments);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<bool> start() async {
|
||||
final result = await _channel.invokeMethod('start');
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
Future<bool> configure({
|
||||
required IosConfiguration iosConfiguration,
|
||||
required AndroidConfiguration androidConfiguration,
|
||||
}) async {
|
||||
_channel.setMethodCallHandler(_handle);
|
||||
|
||||
final CallbackHandle? entryPointHandle =
|
||||
PluginUtilities.getCallbackHandle(_entrypoint);
|
||||
|
||||
final CallbackHandle? handle =
|
||||
PluginUtilities.getCallbackHandle(androidConfiguration.onStart);
|
||||
|
||||
if (entryPointHandle == null || handle == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final result = await _channel.invokeMethod(
|
||||
"configure",
|
||||
{
|
||||
"entrypoint_handle": entryPointHandle.toRawHandle(),
|
||||
"background_handle": handle.toRawHandle(),
|
||||
"is_foreground_mode": androidConfiguration.isForegroundMode,
|
||||
"auto_start_on_boot": androidConfiguration.autoStart,
|
||||
},
|
||||
);
|
||||
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
Future<bool> isServiceRunning() async {
|
||||
var result = await _channel.invokeMethod("isServiceRunning");
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
final _controller = StreamController.broadcast(sync: true);
|
||||
|
||||
void dispose() {
|
||||
_controller.close();
|
||||
}
|
||||
|
||||
@override
|
||||
void invoke(String method, [Map<String, dynamic>? args]) {
|
||||
_channel.invokeMethod("sendData", {
|
||||
'method': method,
|
||||
'args': args,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<Map<String, dynamic>?> on(String method) {
|
||||
return _controller.stream.transform(
|
||||
StreamTransformer.fromHandlers(
|
||||
handleData: (data, sink) {
|
||||
if (data['method'] == method) {
|
||||
sink.add(data['args']);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidServiceInstance extends ServiceInstance {
|
||||
static const MethodChannel _channel = const MethodChannel(
|
||||
'id.flutter/background_service_android_bg',
|
||||
JSONMethodCodec(),
|
||||
);
|
||||
|
||||
AndroidServiceInstance._() {
|
||||
_channel.setMethodCallHandler(_handleMethodCall);
|
||||
}
|
||||
|
||||
final _controller = StreamController.broadcast(sync: true);
|
||||
Future<void> _handleMethodCall(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case "onReceiveData":
|
||||
_controller.sink.add(call.arguments);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void invoke(String method, [Map<String, dynamic>? args]) {
|
||||
_channel.invokeMethod('sendData', {
|
||||
'method': method,
|
||||
'args': args,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopSelf() async {
|
||||
await _channel.invokeMethod("stopService");
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<Map<String, dynamic>?> on(String method) {
|
||||
return _controller.stream.transform(
|
||||
StreamTransformer.fromHandlers(
|
||||
handleData: (data, sink) {
|
||||
if (data['method'] == method) {
|
||||
sink.add(data['args']);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setForegroundNotificationInfo({
|
||||
required String title,
|
||||
required String content,
|
||||
}) async {
|
||||
await _channel.invokeMethod("setNotificationInfo", {
|
||||
"title": title,
|
||||
"content": content,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setAsForegroundService() async {
|
||||
await _channel.invokeMethod("setForegroundMode", {
|
||||
'value': true,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setAsBackgroundService() async {
|
||||
await _channel.invokeMethod("setForegroundMode", {
|
||||
'value': false,
|
||||
});
|
||||
}
|
||||
|
||||
Future<int> _getHandler() async {
|
||||
return await _channel.invokeMethod('getHandler');
|
||||
}
|
||||
|
||||
Future<void> setAutoStartOnBootMode(bool value) async {
|
||||
await _channel.invokeMethod("setAutoStartOnBootMode", {
|
||||
"value": value,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/android/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/android/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/Pods" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/Flutter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/Pods" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/.symlinks" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,63 @@
|
||||
name: flutter_background_service_android
|
||||
description: A flutter plugin for executing dart code continously even application closed.
|
||||
version: 2.0.3
|
||||
repository: https://github.com/ekasetiawans/flutter_background_service
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
flutter: ">=2.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
flutter_background_service_platform_interface: ^2.0.0
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
# This section identifies this Flutter project as a plugin project.
|
||||
# The 'pluginClass' and Android 'package' identifiers should not ordinarily
|
||||
# be modified. They are used by the tooling to maintain consistency when
|
||||
# adding or updating assets for this project.
|
||||
plugin:
|
||||
implements: flutter_background_service
|
||||
platforms:
|
||||
android:
|
||||
package: id.flutter.flutter_background_service
|
||||
pluginClass: FlutterBackgroundServicePlugin
|
||||
dartPluginClass: FlutterBackgroundServiceAndroid
|
||||
# To add assets to your plugin package, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
#
|
||||
# For details regarding assets in packages, see
|
||||
# https://flutter.dev/assets-and-images/#from-packages
|
||||
#
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
# To add custom fonts to your plugin package, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
# "family" key with the font family name, and a "fonts" key with a
|
||||
# list giving the asset and other descriptors for the font. For
|
||||
# example:
|
||||
# fonts:
|
||||
# - family: Schyler
|
||||
# fonts:
|
||||
# - asset: fonts/Schyler-Regular.ttf
|
||||
# - asset: fonts/Schyler-Italic.ttf
|
||||
# style: italic
|
||||
# - family: Trajan Pro
|
||||
# fonts:
|
||||
# - asset: fonts/TrajanPro.ttf
|
||||
# - asset: fonts/TrajanPro_Bold.ttf
|
||||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts in packages, see
|
||||
# https://flutter.dev/custom-fonts/#from-packages
|
@ -0,0 +1 @@
|
||||
void main() {}
|
Loading…
Reference in new issue