├── ios
├── Assets
│ └── .gitkeep
├── .gitignore
├── Classes
│ ├── FBBluetoothStateHandler.h
│ ├── FBRangingStreamHandler.h
│ ├── FBMonitoringStreamHandler.h
│ ├── FBUtils.h
│ ├── FBAuthorizationStatusHandler.h
│ ├── FlutterBeaconPlugin.h
│ ├── FBRangingStreamHandler.m
│ ├── FBMonitoringStreamHandler.m
│ ├── FBBluetoothStateHandler.m
│ ├── FBAuthorizationStatusHandler.m
│ └── FBUtils.m
└── flutter_beacon.podspec
├── android
├── .idea
│ ├── .name
│ ├── caches
│ │ ├── gradle_models.ser
│ │ └── build_file_checksums.ser
│ ├── vcs.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ ├── gradle.xml
│ ├── misc.xml
│ └── codeStyles
│ │ └── Project.xml
├── settings.gradle
├── gradle.properties
├── .gitignore
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── flutterbeacon
│ │ ├── FlutterBluetoothStateReceiver.java
│ │ ├── FlutterBeaconBroadcast.java
│ │ ├── FlutterPlatform.java
│ │ ├── FlutterBeaconUtils.java
│ │ └── FlutterBeaconScanner.java
├── build.gradle
├── gradlew.bat
└── gradlew
├── example
├── test
│ └── widget_test.dart
├── android
│ ├── gradle.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── 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
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── values
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ │ └── flutterbeaconexample
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── settings.gradle
│ └── build.gradle
├── ios
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner
│ │ ├── AppDelegate.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── 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-1024x1024@1x.png
│ │ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ ├── main.m
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ └── Info.plist
│ ├── Runner.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── Podfile
├── .metadata
├── pubspec.yaml
├── lib
│ ├── main.dart
│ ├── controller
│ │ └── requirement_state_controller.dart
│ └── view
│ │ ├── app_scanning.dart
│ │ ├── app_broadcasting.dart
│ │ └── home_page.dart
├── .gitignore
└── README.md
├── AUTHORS
├── scripts
└── credentials.sh
├── .metadata
├── .vscode
└── launch.json
├── pubspec.yaml
├── .github
└── workflows
│ ├── flutter.yaml
│ ├── pub-publish.yaml
│ ├── pub-publish-test.yaml
│ └── coverage-report.yaml
├── test
└── beacon
│ ├── beacon_broadcast_test.dart
│ ├── ranging_result_test.dart
│ ├── region_test.dart
│ ├── authorization_status_test.dart
│ ├── monitoring_result_test.dart
│ ├── bluetooth_state_test.dart
│ └── beacon_test.dart
├── Makefile
├── lib
├── beacon
│ ├── ranging_result.dart
│ ├── beacon_broadcast.dart
│ ├── region.dart
│ ├── monitoring_result.dart
│ ├── authorization_status.dart
│ ├── bluetooth_state.dart
│ └── beacon.dart
└── flutter_beacon.dart
├── CHANGELOG.md
├── flutter_beacon.iml
├── .idea
└── codeStyles
│ └── Project.xml
├── .gitignore
├── README.md
└── LICENSE
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/android/.idea/.name:
--------------------------------------------------------------------------------
1 | flutter_beacon
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | void main() {}
2 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'flutter_beacon'
2 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx1536M
4 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/.idea/caches/gradle_models.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/android/.idea/caches/gradle_models.ser
--------------------------------------------------------------------------------
/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/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/android/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/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/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alann-maulana/flutter_beacon/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | # Below is a list of people and organizations that have contributed
2 | # to the project. Names should be added to the list like so:
3 | #
4 | # Name/Organization
5 |
6 | Alan Maulana
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/scripts/credentials.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [[ ! -e ~/.pub-cache/credentials.json ]]; then
4 | mkdir -p ~/.pub-cache
5 | touch ~/.pub-cache/credentials.json
6 | fi
7 |
8 | echo $PUB_CREDENTIALS > ~/.pub-cache/credentials.json
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/flutterbeaconexample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.flutterbeaconexample
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 | import com.flutterbeacon.FlutterBeaconPlugin;
5 |
6 | class MainActivity: FlutterActivity() {
7 | }
8 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 27 17:17:45 WIB 2019
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-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/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-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/android/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: beta
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_beacon_example
2 | description: Demonstrates how to use the flutter_beacon plugin.
3 | publish_to: 'none'
4 |
5 | environment:
6 | sdk: ">=2.12.0 <3.0.0"
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 |
12 | dev_dependencies:
13 | flutter_test:
14 | sdk: flutter
15 |
16 | flutter_beacon:
17 | path: ../
18 | get: ^4.3.6
19 |
20 | flutter:
21 | uses-material-design: true
22 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "example/lib/main.dart"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Classes/FBBluetoothStateHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // FBBluetoothStateHandler.h
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 24/08/19.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FlutterBeaconPlugin;
14 | @interface FBBluetoothStateHandler : NSObject
15 |
16 | @property (strong, nonatomic) FlutterBeaconPlugin* instance;
17 |
18 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/ios/Classes/FBRangingStreamHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // FBRangingStreamHandler.h
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 23/01/19.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FlutterBeaconPlugin;
14 | @interface FBRangingStreamHandler : NSObject
15 |
16 | @property (strong, nonatomic) FlutterBeaconPlugin* instance;
17 |
18 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/ios/Classes/FBMonitoringStreamHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // FBMonitoringStreamHandler.h
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 23/01/19.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FlutterBeaconPlugin;
14 | @interface FBMonitoringStreamHandler : NSObject
15 |
16 | @property (strong, nonatomic) FlutterBeaconPlugin* instance;
17 |
18 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/ios/Classes/FBUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // FBUtils.h
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 26/12/18.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @class CLBeacon;
13 | @class CLBeaconRegion;
14 | @interface FBUtils : NSObject
15 |
16 | + (NSDictionary * _Nonnull) dictionaryFromCLBeacon:(CLBeacon*) beacon;
17 | + (NSDictionary * _Nonnull) dictionaryFromCLBeaconRegion:(CLBeaconRegion*) region;
18 |
19 | + (CLBeaconRegion * _Nullable) regionFromDictionary:(NSDictionary*) dict;
20 |
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/ios/Classes/FBAuthorizationStatusHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // FBAuthorizationStatusHandler.h
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 15/10/19.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @class FlutterBeaconPlugin;
14 | @interface FBAuthorizationStatusHandler : NSObject
15 |
16 | @property (strong, nonatomic) FlutterBeaconPlugin* instance;
17 |
18 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_beacon
2 | description: Flutter plugin for scanning and transmit as beacon (iBeacon) on Android and iOS.
3 | version: 0.5.1
4 | homepage: https://github.com/alann-maulana/flutter_beacon
5 |
6 | environment:
7 | sdk: ">=2.12.0 <3.0.0"
8 | flutter: ">=1.12.13+hotfix.5"
9 |
10 | dependencies:
11 | flutter:
12 | sdk: flutter
13 |
14 | dev_dependencies:
15 | flutter_test:
16 | sdk: flutter
17 |
18 | flutter:
19 | plugin:
20 | platforms:
21 | android:
22 | package: com.flutterbeacon
23 | pluginClass: FlutterBeaconPlugin
24 | ios:
25 | pluginClass: FlutterBeaconPlugin
26 |
--------------------------------------------------------------------------------
/ios/Classes/FlutterBeaconPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @class CBCentralManager;
4 | @class CBCentralManagerDelegate;
5 | @interface FlutterBeaconPlugin : NSObject
6 |
7 | @property FlutterEventSink flutterEventSinkRanging;
8 | @property FlutterEventSink flutterEventSinkMonitoring;
9 | @property FlutterEventSink flutterEventSinkBluetooth;
10 | @property FlutterEventSink flutterEventSinkAuthorization;
11 |
12 | - (void) initializeCentralManager;
13 | - (void) initializeLocationManager;
14 | - (void) startRangingBeaconWithCall:(id)arguments;
15 | - (void) stopRangingBeacon;
16 | - (void) startMonitoringBeaconWithCall:(id)arguments;
17 | - (void) stopMonitoringBeacon;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/flutter.yaml:
--------------------------------------------------------------------------------
1 | name: Flutter CI
2 |
3 | on:
4 | push:
5 | branches:
6 | master
7 | pull_request:
8 | branches:
9 | master
10 |
11 | jobs:
12 | build:
13 | name: Build & Test on ${{ matrix.os }}
14 | runs-on: ${{ matrix.os }}
15 | strategy:
16 | matrix:
17 | os: [ubuntu-latest, windows-latest, macos-latest]
18 | steps:
19 | - uses: actions/checkout@v2
20 | - uses: actions/setup-java@v1
21 | with:
22 | java-version: '12.x'
23 | - uses: subosito/flutter-action@v1
24 | with:
25 | flutter-version: '2.0.5'
26 | channel: 'stable'
27 | - run: flutter packages get
28 | - run: flutter format --set-exit-if-changed .
29 | - run: flutter analyze .
30 | - run: flutter test
31 |
--------------------------------------------------------------------------------
/.github/workflows/pub-publish.yaml:
--------------------------------------------------------------------------------
1 | name: Pub Publish
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | build:
10 | name: Publishing
11 | runs-on: ubuntu-latest
12 | env:
13 | PUB_CREDENTIALS: ${{ secrets.PUB_CREDENTIALS }}
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: actions/setup-java@v1
17 | with:
18 | java-version: '12.x'
19 | - uses: subosito/flutter-action@v1
20 | with:
21 | flutter-version: '2.0.5'
22 | channel: 'stable'
23 | - name: Documenting package
24 | run: |
25 | echo "FLUTTER_ROOT=$FLUTTER_HOME" >> $GITHUB_ENV
26 | bash scripts/credentials.sh
27 | rm -rf scripts/
28 | make
29 | make deps
30 | pub global activate dartdoc
31 | make docs
32 | pub publish -f -v
33 |
--------------------------------------------------------------------------------
/test/beacon/beacon_broadcast_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_beacon/flutter_beacon.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | main() {
5 | test('main constructor must be equal', () {
6 | final beacon = BeaconBroadcast(
7 | proximityUUID: 'UUID',
8 | major: 1,
9 | minor: 2,
10 | identifier: 'id',
11 | txPower: -58,
12 | advertisingMode: AdvertisingMode.high,
13 | advertisingTxPowerLevel: AdvertisingTxPowerLevel.low,
14 | );
15 |
16 | expect(beacon.proximityUUID, 'UUID');
17 | expect(beacon.major, 1);
18 | expect(beacon.minor, 2);
19 | expect(beacon.identifier, 'id');
20 | expect(beacon.txPower, -58);
21 | expect(beacon.advertisingMode, AdvertisingMode.high);
22 | expect(beacon.advertisingTxPowerLevel, AdvertisingTxPowerLevel.low);
23 | expect(beacon.toJson, isMap);
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | DARTANALYZER_FLAGS=--fatal-warnings
2 |
3 | build: lib/*dart test/*dart deps
4 | dartanalyzer ${DARTANALYZER_FLAGS} lib/
5 | dartfmt -n --set-exit-if-changed lib/ test/
6 | flutter test --coverage --coverage-path ./coverage/lcov.info
7 |
8 | deps: pubspec.yaml
9 | flutter packages get -v
10 |
11 | reformatting:
12 | dartfmt -w lib/ test/
13 |
14 | build-local: reformatting build
15 | genhtml -o coverage coverage/lcov.info
16 | lcov --list coverage/lcov.info
17 | lcov --summary coverage/lcov.info
18 | open coverage/index.html
19 |
20 | pana:
21 | pana -s path .
22 |
23 | docs:
24 | rm -rf doc
25 | pub global run dartdoc --exclude 'dart:async,dart:collection,dart:convert,dart:core,dart:developer,dart:io,dart:isolate,dart:math,dart:typed_data,dart:ui,dart:html_common,dart:ffi,dart:html,dart:js,dart:js_util' --ignore 'ambiguous-doc-reference' --sdk-dir '${FLUTTER_ROOT}/bin/cache/dart-sdk'
26 |
27 | publish:
28 | pub publish
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.flutterbeacon'
2 | version '1.0-SNAPSHOT'
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 |
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.5.1'
11 | }
12 | }
13 | rootProject.allprojects {
14 | repositories {
15 | google()
16 | jcenter()
17 | }
18 | }
19 | apply plugin: 'com.android.library'
20 | android {
21 | compileSdkVersion 30
22 |
23 | defaultConfig {
24 | minSdkVersion 18
25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26 | }
27 | lintOptions {
28 | disable 'InvalidPackage'
29 | }
30 | }
31 |
32 | dependencies {
33 | api 'androidx.legacy:legacy-support-v4:1.0.0'
34 | //api 'org.altbeacon:android-beacon-library:2.16.3'
35 | //api "org.altbeacon:android-beacon-library:2.17.1"
36 | api "org.altbeacon:android-beacon-library:2.19"
37 | }
38 |
--------------------------------------------------------------------------------
/.github/workflows/pub-publish-test.yaml:
--------------------------------------------------------------------------------
1 | name: Pub Publish Test
2 |
3 | on:
4 | push:
5 | branches:
6 | master
7 | pull_request:
8 | branches:
9 | master
10 |
11 | jobs:
12 | build:
13 | name: Publishing Test (Dry Run)
14 | runs-on: ubuntu-latest
15 | env:
16 | PUB_CREDENTIALS: ${{ secrets.PUB_CREDENTIALS }}
17 | steps:
18 | - uses: actions/checkout@v2
19 | - uses: actions/setup-java@v1
20 | with:
21 | java-version: '12.x'
22 | - uses: subosito/flutter-action@v1
23 | with:
24 | flutter-version: '2.0.5'
25 | channel: 'stable'
26 | - name: Documenting package
27 | run: |
28 | echo "FLUTTER_ROOT=$FLUTTER_HOME" >> $GITHUB_ENV
29 | bash scripts/credentials.sh
30 | rm -rf scripts/
31 | make
32 | make deps
33 | pub global activate dartdoc
34 | make docs
35 | pub publish -n -v
36 |
--------------------------------------------------------------------------------
/ios/flutter_beacon.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
3 | #
4 | Pod::Spec.new do |s|
5 | s.name = 'flutter_beacon'
6 | s.version = '0.3.0'
7 | s.summary = 'Flutter plugin for scanning beacon (iBeacon platform) devices on Android and iOS.'
8 | s.description = <<-DESC
9 | Flutter plugin for scanning beacon (iBeacon platform) devices on Android and iOS.
10 | DESC
11 | s.homepage = 'https://github.com/alann-maulana/flutter_beacon'
12 | s.license = { :file => '../LICENSE' }
13 | s.author = { 'Eyro Labs' => 'maulana@cubeacon.com' }
14 | s.source = { :path => '.' }
15 | s.source_files = 'Classes/**/*'
16 | s.public_header_files = 'Classes/**/*.h'
17 | s.dependency 'Flutter'
18 |
19 | s.ios.deployment_target = '8.0'
20 | s.ios.framework = 'CoreLocation',
21 | 'CoreBluetooth'
22 | end
23 |
24 |
--------------------------------------------------------------------------------
/lib/beacon/ranging_result.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Class for managing ranging result from scanning iBeacon process.
8 | class RangingResult {
9 | /// The [Region] of ranging result.
10 | final Region region;
11 |
12 | /// The [List] of [Beacon] detected of ranging result by [Region].
13 | final List beacons;
14 |
15 | /// Constructor for deserialize dynamic json into [RangingResult].
16 | RangingResult.from(dynamic json)
17 | : region = Region.fromJson(json['region']),
18 | beacons = Beacon.beaconFromArray(json['beacons']);
19 |
20 | /// Return the serializable of this object into [Map].
21 | dynamic get toJson => {
22 | 'region': region.toJson,
23 | 'beacons': Beacon.beaconArrayToJson(beacons),
24 | };
25 |
26 | @override
27 | String toString() {
28 | return json.encode(toJson);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/ios/Classes/FBRangingStreamHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // FBRangingStreamHandler.m
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 23/01/19.
6 | //
7 |
8 | #import "FBRangingStreamHandler.h"
9 | #import
10 |
11 | @implementation FBRangingStreamHandler
12 |
13 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance {
14 | if (self = [super init]) {
15 | _instance = instance;
16 | }
17 |
18 | return self;
19 | }
20 |
21 | ///------------------------------------------------------------
22 | #pragma mark - Flutter Stream Handler
23 | ///------------------------------------------------------------
24 |
25 | - (FlutterError * _Nullable)onCancelWithArguments:(id _Nullable)arguments {
26 | if (self.instance) {
27 | [self.instance stopRangingBeacon];
28 | }
29 | return nil;
30 | }
31 |
32 | - (FlutterError * _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events {
33 | if (self.instance) {
34 | self.instance.flutterEventSinkRanging = events;
35 | [self.instance startRangingBeaconWithCall:arguments];
36 | }
37 | return nil;
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/ios/Classes/FBMonitoringStreamHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // FBMonitoringStreamHandler.m
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 23/01/19.
6 | //
7 |
8 | #import "FBMonitoringStreamHandler.h"
9 | #import
10 |
11 | @implementation FBMonitoringStreamHandler
12 |
13 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance {
14 | if (self = [super init]) {
15 | _instance = instance;
16 | }
17 |
18 | return self;
19 | }
20 |
21 | ///------------------------------------------------------------
22 | #pragma mark - Flutter Stream Handler
23 | ///------------------------------------------------------------
24 |
25 | - (FlutterError * _Nullable)onCancelWithArguments:(id _Nullable)arguments {
26 | if (self.instance) {
27 | [self.instance stopMonitoringBeacon];
28 | }
29 | return nil;
30 | }
31 |
32 | - (FlutterError * _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events {
33 | if (self.instance) {
34 | self.instance.flutterEventSinkMonitoring = events;
35 | [self.instance startMonitoringBeaconWithCall:arguments];
36 | }
37 | return nil;
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/ios/Classes/FBBluetoothStateHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // FBBluetoothStateHandler.m
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 24/08/19.
6 | //
7 |
8 | #import "FBBluetoothStateHandler.h"
9 | #import
10 | #import
11 |
12 | @implementation FBBluetoothStateHandler
13 |
14 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance {
15 | if (self = [super init]) {
16 | _instance = instance;
17 | }
18 |
19 | return self;
20 | }
21 |
22 | ///------------------------------------------------------------
23 | #pragma mark - Flutter Stream Handler
24 | ///------------------------------------------------------------
25 |
26 | - (FlutterError * _Nullable)onCancelWithArguments:(id _Nullable)arguments {
27 | if (self.instance) {
28 | self.instance.flutterEventSinkBluetooth = nil;
29 | }
30 | return nil;
31 | }
32 |
33 | - (FlutterError * _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events {
34 | // initialize central manager if it itsn't
35 | [self.instance initializeCentralManager];
36 |
37 | if (self.instance) {
38 | self.instance.flutterEventSinkBluetooth = events;
39 | }
40 |
41 | return nil;
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/ios/Classes/FBAuthorizationStatusHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // FBAuthorizationStatusHandler.m
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 15/10/19.
6 | //
7 |
8 | #import "FBAuthorizationStatusHandler.h"
9 | #import
10 | #import
11 |
12 | @implementation FBAuthorizationStatusHandler
13 |
14 | - (instancetype) initWithFlutterBeaconPlugin:(FlutterBeaconPlugin*) instance {
15 | if (self = [super init]) {
16 | _instance = instance;
17 | }
18 |
19 | return self;
20 | }
21 |
22 | ///------------------------------------------------------------
23 | #pragma mark - Flutter Stream Handler
24 | ///------------------------------------------------------------
25 |
26 | - (FlutterError * _Nullable)onCancelWithArguments:(id _Nullable)arguments {
27 | if (self.instance) {
28 | self.instance.flutterEventSinkAuthorization = nil;
29 | }
30 | return nil;
31 | }
32 |
33 | - (FlutterError * _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events {
34 | // initialize central manager if it itsn't
35 | [self.instance initializeLocationManager];
36 |
37 | if (self.instance) {
38 | self.instance.flutterEventSinkAuthorization = events;
39 | }
40 |
41 | return nil;
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/test/beacon/ranging_result_test.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter_beacon/flutter_beacon.dart';
4 | import 'package:flutter_test/flutter_test.dart';
5 |
6 | main() {
7 | test('MonitoringEventType must equalTo "didEnterRegion', () {
8 | final map = {
9 | 'region': {
10 | 'identifier': 'Cubeacon',
11 | 'proximityUUID': 'CB10023F-A318-3394-4199-A8730C7C1AEC'
12 | },
13 | 'beacons': [
14 | {
15 | 'proximityUUID': 'CB10023F-A318-3394-4199-A8730C7C1AEC',
16 | 'major': 1,
17 | 'minor': 1,
18 | 'rssi': -59,
19 | 'accuracy': 1.2,
20 | 'proximity': 'near',
21 | },
22 | {
23 | 'proximityUUID': 'CB10023F-A318-3394-4199-A8730C7C1AEC',
24 | 'major': 2,
25 | 'minor': 2,
26 | 'rssi': -58,
27 | 'accuracy': 0.8,
28 | 'proximity': 'immediate',
29 | }
30 | ]
31 | };
32 | final enter = RangingResult.from(map);
33 |
34 | expect(enter.region, isNotNull);
35 | expect(enter.region.identifier, 'Cubeacon');
36 | expect(enter.region.proximityUUID, 'CB10023F-A318-3394-4199-A8730C7C1AEC');
37 | expect(enter.beacons, isNotEmpty);
38 | expect(enter.beacons.length, 2);
39 | expect(enter.toJson, map);
40 | expect(enter.toString(), json.encode(map));
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/test/beacon/region_test.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter_beacon/flutter_beacon.dart';
4 | import 'package:flutter_test/flutter_test.dart';
5 |
6 | main() {
7 | test('constructor test must be equal', () {
8 | final map = {
9 | 'identifier': 'ID',
10 | 'proximityUUID': 'UUID',
11 | 'major': 1,
12 | 'minor': 2,
13 | };
14 | final region = Region.fromJson(map);
15 |
16 | expect(region.identifier, 'ID');
17 | expect(region.proximityUUID, 'UUID');
18 | expect(region.major, 1);
19 | expect(region.minor, 2);
20 | expect(region.toJson, map);
21 | expect(region.toString(), json.encode(map));
22 | });
23 |
24 | test('two regions must be equal', () {
25 | final region1 = Region.fromJson({
26 | 'identifier': 'ID',
27 | 'proximityUUID': 'UUID',
28 | 'major': '1',
29 | 'minor': '2',
30 | });
31 | final region2 = Region(
32 | identifier: 'ID',
33 | proximityUUID: 'UUID',
34 | major: 1,
35 | minor: 2,
36 | );
37 |
38 | expect(region1.identifier, region2.identifier);
39 | expect(region1.proximityUUID, region2.proximityUUID);
40 | expect(region1.major, region2.major);
41 | expect(region1.minor, region2.minor);
42 | expect(region1 == region2, isTrue);
43 | expect(region1.hashCode == region2.hashCode, isTrue);
44 | });
45 | }
46 |
--------------------------------------------------------------------------------
/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 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
32 | end
33 |
34 | post_install do |installer|
35 | installer.pods_project.targets.each do |target|
36 | flutter_additional_ios_build_settings(target)
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_beacon_example/controller/requirement_state_controller.dart';
4 | import 'package:flutter_beacon_example/view/home_page.dart';
5 | import 'package:get/get.dart';
6 |
7 | void main() {
8 | runApp(MainApp());
9 | }
10 |
11 | class MainApp extends StatelessWidget {
12 | @override
13 | Widget build(BuildContext context) {
14 | Get.put(RequirementStateController());
15 |
16 | final themeData = Theme.of(context);
17 | final primary = Colors.blue;
18 |
19 | return GetMaterialApp(
20 | theme: ThemeData(
21 | brightness: Brightness.light,
22 | primarySwatch: primary,
23 | appBarTheme: themeData.appBarTheme.copyWith(
24 | brightness: Brightness.light,
25 | elevation: 0.5,
26 | color: Colors.white,
27 | actionsIconTheme: themeData.primaryIconTheme.copyWith(
28 | color: primary,
29 | ),
30 | iconTheme: themeData.primaryIconTheme.copyWith(
31 | color: primary,
32 | ),
33 | textTheme: themeData.primaryTextTheme.copyWith(
34 | headline6: themeData.textTheme.headline6?.copyWith(
35 | color: primary,
36 | ),
37 | ),
38 | ),
39 | ),
40 | darkTheme: ThemeData(
41 | brightness: Brightness.dark,
42 | primarySwatch: primary,
43 | ),
44 | home: HomePage(),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 |
40 | # iOS/XCode related
41 | **/ios/**/*.mode1v3
42 | **/ios/**/*.mode2v3
43 | **/ios/**/*.moved-aside
44 | **/ios/**/*.pbxuser
45 | **/ios/**/*.perspectivev3
46 | **/ios/**/*sync/
47 | **/ios/**/.sconsign.dblite
48 | **/ios/**/.tags*
49 | **/ios/**/.vagrant/
50 | **/ios/**/DerivedData/
51 | **/ios/**/Icon?
52 | **/ios/**/Pods/
53 | **/ios/**/.symlinks/
54 | **/ios/**/profile
55 | **/ios/**/xcuserdata
56 | **/ios/.generated/
57 | **/ios/Flutter/App.framework
58 | **/ios/Flutter/Flutter.framework
59 | **/ios/Flutter/Generated.xcconfig
60 | **/ios/Flutter/app.flx
61 | **/ios/Flutter/app.zip
62 | **/ios/Flutter/flutter_assets/
63 | **/ios/ServiceDefinitions.json
64 | **/ios/Runner/GeneratedPluginRegistrant.*
65 |
66 | # Exceptions to above rules.
67 | !**/ios/**/default.mode1v3
68 | !**/ios/**/default.mode2v3
69 | !**/ios/**/default.pbxuser
70 | !**/ios/**/default.perspectivev3
71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
72 | ios/Flutter/Flutter.podspec
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | ### Initializing Library
2 |
3 | ```dart
4 | try {
5 | await flutterBeacon.initializeScanning;
6 | } on PlatformException catch(e) {
7 | // library failed to initialize, check code and message
8 | }
9 | ```
10 |
11 | ### Ranging beacons
12 |
13 | ```dart
14 | final regions = [];
15 |
16 | if (Platform.isIOS) {
17 | regions.add(Region(
18 | identifier: 'Apple Airlocate',
19 | proximityUUID: 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'));
20 | } else {
21 | // android platform, it can ranging out of beacon that filter all of Proximity UUID
22 | regions.add(Region(identifier: 'com.beacon'));
23 | }
24 |
25 | // to start ranging beacons
26 | _streamRanging = flutterBeacon.ranging(regions).listen((RangingResult result) {
27 | // result contains a region and list of beacons found
28 | // list can be empty if no matching beacons were found in range
29 | });
30 |
31 | // to stop ranging beacons
32 | _streamRanging.cancel();
33 | ```
34 |
35 | ### Monitoring beacons
36 |
37 | ```dart
38 | final regions = [];
39 |
40 | if (Platform.isIOS) {
41 | regions.add(Region(
42 | identifier: 'Apple Airlocate',
43 | proximityUUID: 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'));
44 | } else {
45 | // android platform, it can ranging out of beacon that filter all of Proximity UUID
46 | regions.add(Region(identifier: 'com.beacon'));
47 | }
48 |
49 | // to start monitoring beacons
50 | _streamMonitoring = flutterBeacon.monitoring(regions).listen((MonitoringResult result) {
51 | // result contains a region, event type and event state
52 | });
53 |
54 | // to stop monitoring beacons
55 | _streamMonitoring.cancel();
56 | ```
57 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.5.1]
2 | * Migration the example to null safety and to Android v2 embedding
3 | * Update Android-Beacon-Library to version [2.19] with added support to Android 12 (https://github.com/AltBeacon/android-beacon-library/tree/2.19)
4 | * Update README.md with new Android permission requirement for location (SDK 29+, Android 10, 11)
5 |
6 | ## [0.5.0]
7 | * Migration to null safety
8 |
9 | ## [0.4.0]
10 | * Update to Android v2 embedding
11 | * Add broadcast Beacon feature
12 | * Improve example app
13 |
14 | ## [0.3.0]
15 | * Update Android-Beacon-Library to version [2.16.3](https://github.com/AltBeacon/android-beacon-library/tree/2.16.3)
16 | * Add `BluetoothState` event channel
17 | * Add `AuthorizationStatus` event channel [iOS only]
18 | * Add manual check for `AuthorizationStatus`, `BluetoothState`, Location Service.
19 | * Add opener settings for Bluetooth [Android], Location [Android] and Application [iOS].
20 | * A lot of improvements
21 |
22 | ## [0.2.4]
23 |
24 | * Fix bugs
25 | * Add `close` scanning API
26 |
27 | ## [0.2.3]
28 |
29 | * Update gradle build to latest version
30 | * Update stop
31 |
32 | ## [0.2.2]
33 |
34 | * Update gradle to latest version
35 | * Update Android-Beacon-Library to version [2.16.1](https://github.com/AltBeacon/android-beacon-library/tree/2.16.1)
36 |
37 | ## [0.2.1]
38 |
39 | * Fix crash ranging when region not set for Android
40 |
41 | ## [0.2.0]
42 |
43 | * Migrate to AndroidX
44 |
45 | ## [0.1.1]
46 |
47 | * Fix region ranging for Android
48 |
49 | ## [0.1.0]
50 |
51 | * Updating library docs
52 | * Adding example docs
53 |
54 | ## [0.0.2]
55 |
56 | * Adding Dart Docs
57 |
58 | ## [0.0.1]
59 |
60 | * Initial release
61 | * Ranging iBeacons for iOS and Android
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.github/workflows/coverage-report.yaml:
--------------------------------------------------------------------------------
1 | name: Coverage Coverage Report
2 |
3 | on:
4 | push:
5 | branches:
6 | master
7 | pull_request:
8 | branches:
9 | master
10 |
11 | jobs:
12 | codecov_io:
13 | name: "Codecov.io"
14 | runs-on: ubuntu-latest
15 | env:
16 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
17 | steps:
18 | - uses: actions/checkout@v2
19 | - uses: actions/setup-java@v1
20 | with:
21 | java-version: '12.x'
22 | - uses: subosito/flutter-action@v1
23 | with:
24 | flutter-version: '2.0.5'
25 | channel: 'stable'
26 | - name: Generate coverage report
27 | run: flutter test --coverage --coverage-path ./coverage/lcov.info
28 | - name: Send to codecov.io
29 | run: bash <(curl -s https://codecov.io/bash)
30 | - run: ls -al ./coverage
31 | - name: "Upload coverage"
32 | uses: actions/upload-artifact@v1
33 | with:
34 | name: coverage
35 | path: ./coverage
36 |
37 | coveralls_io:
38 | name: "Coveralls.io"
39 | needs: codecov_io
40 | runs-on: ubuntu-latest
41 | steps:
42 | - uses: actions/checkout@v2
43 | - name: "Download coverage"
44 | uses: actions/download-artifact@v1
45 | with:
46 | name: coverage
47 | path: ./coverage
48 | - name: "Setup ruby"
49 | uses: actions/setup-ruby@v1
50 | with:
51 | ruby-version: '2.6'
52 | - run: gem install coveralls-lcov
53 | - run: cat ./coverage/lcov.info
54 | - name: Send to coveralls.io
55 | run: coveralls-lcov --verbose --repo-token $COVERALLS_TOKEN coverage/lcov.info
56 | env:
57 | COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
58 |
--------------------------------------------------------------------------------
/example/lib/controller/requirement_state_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_beacon/flutter_beacon.dart';
2 | import 'package:get/get.dart';
3 |
4 | class RequirementStateController extends GetxController {
5 | var bluetoothState = BluetoothState.stateOff.obs;
6 | var authorizationStatus = AuthorizationStatus.notDetermined.obs;
7 | var locationService = false.obs;
8 |
9 | var _startBroadcasting = false.obs;
10 | var _startScanning = false.obs;
11 | var _pauseScanning = false.obs;
12 |
13 | bool get bluetoothEnabled => bluetoothState.value == BluetoothState.stateOn;
14 | bool get authorizationStatusOk =>
15 | authorizationStatus.value == AuthorizationStatus.allowed ||
16 | authorizationStatus.value == AuthorizationStatus.always;
17 | bool get locationServiceEnabled => locationService.value;
18 |
19 | updateBluetoothState(BluetoothState state) {
20 | bluetoothState.value = state;
21 | }
22 |
23 | updateAuthorizationStatus(AuthorizationStatus status) {
24 | authorizationStatus.value = status;
25 | }
26 |
27 | updateLocationService(bool flag) {
28 | locationService.value = flag;
29 | }
30 |
31 | startBroadcasting() {
32 | _startBroadcasting.value = true;
33 | }
34 |
35 | stopBroadcasting() {
36 | _startBroadcasting.value = false;
37 | }
38 |
39 | startScanning() {
40 | _startScanning.value = true;
41 | _pauseScanning.value = false;
42 | }
43 |
44 | pauseScanning() {
45 | _startScanning.value = false;
46 | _pauseScanning.value = true;
47 | }
48 |
49 | Stream get startBroadcastStream {
50 | return _startBroadcasting.stream;
51 | }
52 |
53 | Stream get startStream {
54 | return _startScanning.stream;
55 | }
56 |
57 | Stream get pauseStream {
58 | return _pauseScanning.stream;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 30
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | defaultConfig {
36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
37 | applicationId "com.example.flutter_beacon_example"
38 | minSdkVersion 18
39 | targetSdkVersion 30
40 | versionCode flutterVersionCode.toInteger()
41 | versionName flutterVersionName
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
59 | }
60 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Flutter Beacon
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | Flutter Beacon
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | NSBluetoothAlwaysUsageDescription
28 | This app need to scan beacons.
29 | NSLocationAlwaysAndWhenInUseUsageDescription
30 | This app need to scan beacons.
31 | NSLocationAlwaysUsageDescription
32 | This app need to scan beacons.
33 | NSLocationWhenInUseUsageDescription
34 | This app need to scan beacons.
35 | UILaunchStoryboardName
36 | LaunchScreen
37 | UIMainStoryboardFile
38 | Main
39 | UISupportedInterfaceOrientations
40 |
41 | UIInterfaceOrientationPortrait
42 |
43 | UISupportedInterfaceOrientations~ipad
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UIViewControllerBasedStatusBarAppearance
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/lib/beacon/beacon_broadcast.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Class for managing Beacon Broadcast object.
8 | class BeaconBroadcast {
9 | /// The unique identifier of region.
10 | final String? identifier;
11 |
12 | /// The proximity UUID of beacon.
13 | final String proximityUUID;
14 |
15 | /// The major value of beacon.
16 | final int major;
17 |
18 | /// The minor value of beacon.
19 | final int minor;
20 |
21 | /// The txPower value of beacon. Specify null to use the default value for the device.
22 | final int? txPower;
23 |
24 | final AdvertisingMode? advertisingMode;
25 |
26 | final AdvertisingTxPowerLevel? advertisingTxPowerLevel;
27 |
28 | BeaconBroadcast({
29 | this.identifier = 'com.flutterBeacon',
30 | required this.proximityUUID,
31 | required this.major,
32 | required this.minor,
33 | this.txPower,
34 | this.advertisingMode = AdvertisingMode.low,
35 | this.advertisingTxPowerLevel = AdvertisingTxPowerLevel.high,
36 | }) {
37 | if (Platform.isAndroid) {
38 | assert(advertisingMode != null);
39 | assert(advertisingTxPowerLevel != null);
40 | } else if (Platform.isIOS) {
41 | assert(identifier != null);
42 | }
43 | }
44 |
45 | /// Serialize current instance object into [Map].
46 | dynamic get toJson {
47 | final map = {
48 | 'proximityUUID': proximityUUID,
49 | 'major': major,
50 | 'minor': minor,
51 | 'txPower': txPower,
52 | };
53 |
54 | if (advertisingMode != null) {
55 | map['advertisingMode'] = advertisingMode!.index;
56 | }
57 |
58 | if (advertisingTxPowerLevel != null) {
59 | map['advertisingTxPowerLevel'] = advertisingTxPowerLevel!.index;
60 | }
61 |
62 | if (identifier != null) {
63 | map['identifier'] = identifier!;
64 | }
65 |
66 | return map;
67 | }
68 | }
69 |
70 | enum AdvertisingMode { low, mid, high }
71 |
72 | enum AdvertisingTxPowerLevel { ultraLow, low, mid, high }
73 |
--------------------------------------------------------------------------------
/flutter_beacon.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/test/beacon/authorization_status_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_beacon/flutter_beacon.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | void main() {
5 | test('authorization initialization', () {
6 | final authorizationStatus = AuthorizationStatus.init(
7 | 'VALUE',
8 | isAndroid: true,
9 | isIOS: true,
10 | );
11 | expect(authorizationStatus.value, 'VALUE');
12 | expect(authorizationStatus.isAndroid, isTrue);
13 | expect(authorizationStatus.isIOS, isTrue);
14 | });
15 |
16 | test('authorization must be equal', () {
17 | final statusA = AuthorizationStatus.init(
18 | 'VALUE',
19 | isAndroid: false,
20 | isIOS: true,
21 | );
22 | final statusB = AuthorizationStatus.init(
23 | 'VALUE',
24 | isAndroid: false,
25 | isIOS: true,
26 | );
27 | expect(statusA, statusB);
28 | expect(statusA.hashCode, statusB.hashCode);
29 | expect(statusA.value, statusB.value);
30 | expect(statusA.isAndroid, statusB.isAndroid);
31 | expect(statusA.isIOS, statusB.isIOS);
32 | expect(statusA.toString(), statusB.toString());
33 | });
34 |
35 | test('authorization value', () {
36 | expect(AuthorizationStatus.allowed.value, 'ALLOWED');
37 | expect(AuthorizationStatus.always.value, 'ALWAYS');
38 | expect(AuthorizationStatus.whenInUse.value, 'WHEN_IN_USE');
39 | expect(AuthorizationStatus.denied.value, 'DENIED');
40 | expect(AuthorizationStatus.restricted.value, 'RESTRICTED');
41 | expect(AuthorizationStatus.notDetermined.value, 'NOT_DETERMINED');
42 | });
43 |
44 | test('parse authorization value', () {
45 | expect(AuthorizationStatus.parse('ALLOWED'), AuthorizationStatus.allowed);
46 | expect(AuthorizationStatus.parse('ALWAYS'), AuthorizationStatus.always);
47 | expect(AuthorizationStatus.parse('WHEN_IN_USE'),
48 | AuthorizationStatus.whenInUse);
49 | expect(AuthorizationStatus.parse('DENIED'), AuthorizationStatus.denied);
50 | expect(AuthorizationStatus.parse('RESTRICTED'),
51 | AuthorizationStatus.restricted);
52 | expect(AuthorizationStatus.parse('NOT_DETERMINED'),
53 | AuthorizationStatus.notDetermined);
54 | expect(() => AuthorizationStatus.parse('null'), throwsException);
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/test/beacon/monitoring_result_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_beacon/flutter_beacon.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | main() {
5 | test('MonitoringEventType must equalTo "didEnterRegion', () {
6 | final map = {
7 | 'region': {
8 | 'identifier': 'id',
9 | 'proximityUUID': 'UUID',
10 | },
11 | 'event': 'didEnterRegion',
12 | };
13 | final enter = MonitoringResult.from(map);
14 |
15 | expect(enter.region, isNotNull);
16 | expect(enter.region.identifier, 'id');
17 | expect(enter.region.proximityUUID, 'UUID');
18 | expect(enter.monitoringEventType, MonitoringEventType.didEnterRegion);
19 | expect(enter.toJson, map);
20 | });
21 |
22 | test('MonitoringEventType must equalTo "didExitRegion', () {
23 | final map = {
24 | 'region': {
25 | 'identifier': 'id',
26 | 'proximityUUID': 'UUID',
27 | },
28 | 'event': 'didExitRegion',
29 | };
30 | final enter = MonitoringResult.from(map);
31 |
32 | expect(enter.region, isNotNull);
33 | expect(enter.region.identifier, 'id');
34 | expect(enter.region.proximityUUID, 'UUID');
35 | expect(enter.monitoringEventType, MonitoringEventType.didExitRegion);
36 | expect(enter.toJson, map);
37 | });
38 |
39 | test('MonitoringEventType must equalTo "didDetermineStateForRegion', () {
40 | final map = {
41 | 'region': {
42 | 'identifier': 'id',
43 | 'proximityUUID': 'UUID',
44 | },
45 | 'state': 'unknown',
46 | 'event': 'didDetermineStateForRegion',
47 | };
48 | final enter = MonitoringResult.from(map);
49 |
50 | expect(enter.region, isNotNull);
51 | expect(enter.region.identifier, 'id');
52 | expect(enter.region.proximityUUID, 'UUID');
53 | expect(enter.monitoringEventType,
54 | MonitoringEventType.didDetermineStateForRegion);
55 | expect(enter.monitoringState, MonitoringState.unknown);
56 | expect(enter.toJson, map);
57 | });
58 |
59 | test('MonitoringResult must throw', () {
60 | final map = {
61 | 'region': {
62 | 'identifier': 'id',
63 | 'proximityUUID': 'UUID',
64 | },
65 | 'state': 'unknown',
66 | 'event': 'null',
67 | };
68 |
69 | expect(() => MonitoringResult.from(map), throwsException);
70 | });
71 | }
72 |
--------------------------------------------------------------------------------
/test/beacon/bluetooth_state_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_beacon/flutter_beacon.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | void main() {
5 | test('bluetooth state initialization', () {
6 | final bluetoothState = BluetoothState.init(
7 | 'VALUE',
8 | isAndroid: true,
9 | isIOS: true,
10 | );
11 | expect(bluetoothState.value, 'VALUE');
12 | expect(bluetoothState.isAndroid, isTrue);
13 | expect(bluetoothState.isIOS, isTrue);
14 | });
15 |
16 | test('bluetooth state must be equal', () {
17 | final stateA = BluetoothState.init(
18 | 'VALUE',
19 | isAndroid: true,
20 | isIOS: false,
21 | );
22 | final stateB = BluetoothState.init(
23 | 'VALUE',
24 | isAndroid: true,
25 | isIOS: false,
26 | );
27 | expect(stateA, stateB);
28 | expect(stateA.hashCode, stateB.hashCode);
29 | expect(stateA.value, stateB.value);
30 | expect(stateA.isAndroid, stateB.isAndroid);
31 | expect(stateA.isIOS, stateB.isIOS);
32 | expect(stateA.toString(), stateB.toString());
33 | });
34 |
35 | test('bluetooth state value', () {
36 | expect(BluetoothState.stateOff.value, 'STATE_OFF');
37 | expect(BluetoothState.stateTurningOff.value, 'STATE_TURNING_OFF');
38 | expect(BluetoothState.stateOn.value, 'STATE_ON');
39 | expect(BluetoothState.stateTurningOn.value, 'STATE_TURNING_ON');
40 | expect(BluetoothState.stateUnknown.value, 'STATE_UNKNOWN');
41 | expect(BluetoothState.stateResetting.value, 'STATE_RESETTING');
42 | expect(BluetoothState.stateUnsupported.value, 'STATE_UNSUPPORTED');
43 | expect(BluetoothState.stateUnauthorized.value, 'STATE_UNAUTHORIZED');
44 | });
45 |
46 | test('parse bluetooth state value', () {
47 | expect(BluetoothState.parse('STATE_OFF'), BluetoothState.stateOff);
48 | expect(BluetoothState.parse('STATE_TURNING_OFF'),
49 | BluetoothState.stateTurningOff);
50 | expect(BluetoothState.parse('STATE_ON'), BluetoothState.stateOn);
51 | expect(BluetoothState.parse('STATE_TURNING_ON'),
52 | BluetoothState.stateTurningOn);
53 | expect(BluetoothState.parse('STATE_UNKNOWN'), BluetoothState.stateUnknown);
54 | expect(
55 | BluetoothState.parse('STATE_RESETTING'), BluetoothState.stateResetting);
56 | expect(BluetoothState.parse('STATE_UNSUPPORTED'),
57 | BluetoothState.stateUnsupported);
58 | expect(BluetoothState.parse('STATE_UNAUTHORIZED'),
59 | BluetoothState.stateUnauthorized);
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/android/src/main/java/com/flutterbeacon/FlutterBluetoothStateReceiver.java:
--------------------------------------------------------------------------------
1 | package com.flutterbeacon;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.bluetooth.BluetoothAdapter;
5 | import android.bluetooth.BluetoothManager;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 |
11 | import io.flutter.plugin.common.EventChannel;
12 |
13 | class FlutterBluetoothStateReceiver extends BroadcastReceiver implements EventChannel.StreamHandler {
14 | private final Context context;
15 | private EventChannel.EventSink eventSink;
16 |
17 | public FlutterBluetoothStateReceiver(Context context) {
18 | this.context = context;
19 | }
20 |
21 | @Override
22 | public void onReceive(Context context, Intent intent) {
23 | if (eventSink == null) return;
24 | final String action = intent.getAction();
25 |
26 | if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
27 | final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
28 | sendState(state);
29 | }
30 | }
31 |
32 | private void sendState(int state) {
33 | switch (state) {
34 | case BluetoothAdapter.STATE_OFF:
35 | eventSink.success("STATE_OFF");
36 | break;
37 | case BluetoothAdapter.STATE_TURNING_OFF:
38 | eventSink.success("STATE_TURNING_OFF");
39 | break;
40 | case BluetoothAdapter.STATE_ON:
41 | eventSink.success("STATE_ON");
42 | break;
43 | case BluetoothAdapter.STATE_TURNING_ON:
44 | eventSink.success("STATE_TURNING_ON");
45 | break;
46 | default:
47 | eventSink.error("BLUETOOTH_STATE", "invalid bluetooth adapter state", null);
48 | break;
49 | }
50 | }
51 |
52 | @SuppressLint("MissingPermission")
53 | @Override
54 | public void onListen(Object o, EventChannel.EventSink eventSink) {
55 | int state = BluetoothAdapter.STATE_OFF;
56 |
57 | BluetoothManager bluetoothManager = (BluetoothManager)
58 | context.getSystemService(Context.BLUETOOTH_SERVICE);
59 | if (bluetoothManager != null) {
60 | BluetoothAdapter adapter = bluetoothManager.getAdapter();
61 | if (adapter != null) {
62 | state = adapter.getState();
63 | }
64 | }
65 | this.eventSink = eventSink;
66 | this.sendState(state);
67 |
68 | IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
69 | context.registerReceiver(this, filter);
70 | }
71 |
72 | @Override
73 | public void onCancel(Object o) {
74 | context.unregisterReceiver(this);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ios/Classes/FBUtils.m:
--------------------------------------------------------------------------------
1 | //
2 | // FBUtils.m
3 | // flutter_beacon
4 | //
5 | // Created by Alann Maulana on 26/12/18.
6 | //
7 |
8 | #import "FBUtils.h"
9 | #import
10 |
11 | @implementation FBUtils
12 |
13 | + (NSDictionary * _Nonnull) dictionaryFromCLBeacon:(CLBeacon*) beacon {
14 | NSString *proximity;
15 | switch (beacon.proximity) {
16 | case CLProximityUnknown:
17 | proximity = @"unknown";
18 | break;
19 | case CLProximityImmediate:
20 | proximity = @"immediate";
21 | break;
22 | case CLProximityNear:
23 | proximity = @"near";
24 | break;
25 | case CLProximityFar:
26 | proximity = @"far";
27 | break;
28 | }
29 |
30 | NSNumber *rssi = [NSNumber numberWithInteger:beacon.rssi];
31 | return @{
32 | @"proximityUUID": [beacon.proximityUUID UUIDString],
33 | @"major": beacon.major,
34 | @"minor": beacon.minor,
35 | @"rssi": rssi,
36 | @"accuracy": [NSString stringWithFormat:@"%.2f", beacon.accuracy],
37 | @"proximity": proximity
38 | };
39 | }
40 |
41 | + (NSDictionary * _Nonnull) dictionaryFromCLBeaconRegion:(CLBeaconRegion*) region {
42 | id major = region.major;
43 | if (!major) {
44 | major = [NSNull null];
45 | }
46 | id minor = region.minor;
47 | if (!minor) {
48 | minor = [NSNull null];
49 | }
50 |
51 | return @{
52 | @"identifier": region.identifier,
53 | @"proximityUUID": [region.proximityUUID UUIDString],
54 | @"major": major,
55 | @"minor": minor,
56 | };
57 | }
58 |
59 | + (CLBeaconRegion * _Nullable) regionFromDictionary:(NSDictionary*) dict {
60 | NSString *identifier = dict[@"identifier"];
61 | NSString *proximityUUID = dict[@"proximityUUID"];
62 | NSNumber *major = dict[@"major"];
63 | NSNumber *minor = dict[@"minor"];
64 |
65 | CLBeaconRegion *region = nil;
66 | if (proximityUUID && major && minor) {
67 | region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:proximityUUID] major:[major intValue] minor:[minor intValue] identifier:identifier];
68 | } else if (proximityUUID && major) {
69 | region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:proximityUUID] major:[major intValue] identifier:identifier];
70 | } else if (proximityUUID) {
71 | region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:proximityUUID] identifier:identifier];
72 | }
73 |
74 | return region;
75 | }
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/lib/beacon/region.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Class for managing for ranging and monitoring region scanning.
8 | class Region {
9 | /// The unique identifier of region.
10 | final String identifier;
11 |
12 | /// The proximity UUID of region.
13 | ///
14 | /// For iOS, this value can not be null.
15 | final String? proximityUUID;
16 |
17 | /// The major number of region.
18 | ///
19 | /// For both Android and iOS, this value can be null.
20 | final int? major;
21 |
22 | /// The minor number of region.
23 | ///
24 | /// For both Android and iOS, this value can be null.
25 | final int? minor;
26 |
27 | /// Constructor for creating [Region] object.
28 | ///
29 | /// The [proximityUUID] must not be null when [Platform.isIOS]
30 | Region({
31 | required this.identifier,
32 | this.proximityUUID,
33 | this.major,
34 | this.minor,
35 | }) {
36 | if (Platform.isIOS) {
37 | assert(
38 | proximityUUID != null,
39 | 'Scanning beacon for iOS must provided proximityUUID',
40 | );
41 | }
42 | }
43 |
44 | /// Constructor for deserialize json [Map] into [Region] object.
45 | Region.fromJson(dynamic json)
46 | : this(
47 | identifier: json['identifier'],
48 | proximityUUID: json['proximityUUID'],
49 | major: _parseMajorMinor(json['major']),
50 | minor: _parseMajorMinor(json['minor']),
51 | );
52 |
53 | /// Return the serializable of this object into [Map].
54 | dynamic get toJson {
55 | final map = {
56 | 'identifier': identifier,
57 | };
58 |
59 | if (proximityUUID != null) {
60 | map['proximityUUID'] = proximityUUID;
61 | }
62 |
63 | if (major != null) {
64 | map['major'] = major;
65 | }
66 |
67 | if (minor != null) {
68 | map['minor'] = minor;
69 | }
70 |
71 | return map;
72 | }
73 |
74 | @override
75 | bool operator ==(Object other) =>
76 | identical(this, other) ||
77 | other is Region &&
78 | runtimeType == other.runtimeType &&
79 | identifier == other.identifier;
80 |
81 | @override
82 | int get hashCode => identifier.hashCode;
83 |
84 | static int? _parseMajorMinor(dynamic number) {
85 | if (number is num) {
86 | return number.toInt();
87 | }
88 |
89 | if (number is String) {
90 | return int.tryParse(number);
91 | }
92 |
93 | return null;
94 | }
95 |
96 | @override
97 | String toString() {
98 | return json.encode(toJson);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/beacon/monitoring_result.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Enum for defining monitoring event type.
8 | enum MonitoringEventType {
9 | didEnterRegion,
10 | didExitRegion,
11 | didDetermineStateForRegion
12 | }
13 |
14 | /// Enum for defining monitoring state
15 | enum MonitoringState { inside, outside, unknown }
16 |
17 | /// Class for managing monitoring result from scanning iBeacon process.
18 | class MonitoringResult {
19 | /// The [MonitoringEventType] of monitoring result
20 | final MonitoringEventType monitoringEventType;
21 |
22 | /// The [MonitoringState] of monitoring result
23 | ///
24 | /// This value is not null when [monitoringEventType] is [MonitoringEventType.didDetermineStateForRegion]
25 | final MonitoringState? monitoringState;
26 |
27 | /// The [Region] of ranging result.
28 | final Region region;
29 |
30 | /// Constructor for deserialize dynamic json into [MonitoringResult].
31 | MonitoringResult.from(dynamic json)
32 | : this.monitoringEventType = _parseMonitoringEventType(json['event']),
33 | this.monitoringState = _parseMonitoringState(json['state']),
34 | this.region = Region.fromJson(json['region']);
35 |
36 | /// Parsing dynamic state into [MonitoringState].
37 | static MonitoringState? _parseMonitoringState(dynamic state) {
38 | if (!(state is String)) {
39 | return null;
40 | }
41 |
42 | if (state.toLowerCase() == 'inside') {
43 | return MonitoringState.inside;
44 | } else if (state.toLowerCase() == 'outside') {
45 | return MonitoringState.outside;
46 | } else if (state.toLowerCase() == 'unknown') {
47 | return MonitoringState.unknown;
48 | }
49 |
50 | return null;
51 | }
52 |
53 | /// Parsing dynamic event into [MonitoringEventType]
54 | static MonitoringEventType _parseMonitoringEventType(dynamic event) {
55 | if (event == 'didEnterRegion') {
56 | return MonitoringEventType.didEnterRegion;
57 | } else if (event == 'didExitRegion') {
58 | return MonitoringEventType.didExitRegion;
59 | } else if (event == 'didDetermineStateForRegion') {
60 | return MonitoringEventType.didDetermineStateForRegion;
61 | }
62 |
63 | throw Exception('invalid monitoring event type $event');
64 | }
65 |
66 | /// Return the serializable of this object into [Map].
67 | dynamic get toJson {
68 | final map = {
69 | 'event': monitoringEventType.toString().split('.').last,
70 | 'region': region.toJson,
71 | };
72 |
73 | if (monitoringState != null) {
74 | map['state'] = monitoringState.toString().split('.').last;
75 | }
76 |
77 | return map;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/android/.idea/misc.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 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/src/main/java/com/flutterbeacon/FlutterBeaconBroadcast.java:
--------------------------------------------------------------------------------
1 | package com.flutterbeacon;
2 |
3 | import android.app.Activity;
4 | import android.bluetooth.le.AdvertiseCallback;
5 | import android.bluetooth.le.AdvertiseSettings;
6 | import android.os.Build;
7 | import android.util.Log;
8 |
9 | import androidx.annotation.NonNull;
10 |
11 | import org.altbeacon.beacon.Beacon;
12 | import org.altbeacon.beacon.BeaconParser;
13 | import org.altbeacon.beacon.BeaconTransmitter;
14 |
15 | import java.util.Map;
16 |
17 | import io.flutter.plugin.common.MethodChannel;
18 |
19 | class FlutterBeaconBroadcast {
20 | private static final String TAG = FlutterBeaconBroadcast.class.getSimpleName();
21 | private final BeaconTransmitter beaconTransmitter;
22 |
23 | FlutterBeaconBroadcast(Activity activity, BeaconParser iBeaconLayout) {
24 | this.beaconTransmitter = new BeaconTransmitter(activity, iBeaconLayout);
25 | }
26 |
27 | void isBroadcasting(@NonNull MethodChannel.Result result) {
28 | result.success(beaconTransmitter.isStarted());
29 | }
30 |
31 | void stopBroadcast(@NonNull MethodChannel.Result result) {
32 | beaconTransmitter.stopAdvertising();
33 | result.success(true);
34 | }
35 |
36 | @SuppressWarnings("rawtypes")
37 | void startBroadcast(Object arguments, @NonNull final MethodChannel.Result result) {
38 | if (!(arguments instanceof Map)) {
39 | result.error("Broadcast", "Invalid parameter", null);
40 | return;
41 | }
42 |
43 | Map map = (Map) arguments;
44 | final Beacon beacon = FlutterBeaconUtils.beaconFromMap(map);
45 |
46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
47 | Object advertisingMode = map.get("advertisingMode");
48 | if (advertisingMode instanceof Integer) {
49 | beaconTransmitter.setAdvertiseMode((Integer) advertisingMode);
50 | }
51 | Object advertisingTxPowerLevel = map.get("advertisingTxPowerLevel");
52 | if (advertisingTxPowerLevel instanceof Integer) {
53 | beaconTransmitter.setAdvertiseTxPowerLevel((Integer) advertisingTxPowerLevel);
54 | }
55 | beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
56 | @Override
57 | public void onStartSuccess(AdvertiseSettings settingsInEffect) {
58 | Log.d(TAG, "Start broadcasting = " + beacon);
59 | result.success(true);
60 | }
61 |
62 | @Override
63 | public void onStartFailure(int errorCode) {
64 | String error = "FEATURE_UNSUPPORTED";
65 | if (errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE) {
66 | error = "DATA_TOO_LARGE";
67 | } else if (errorCode == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
68 | error = "TOO_MANY_ADVERTISERS";
69 | } else if (errorCode == ADVERTISE_FAILED_ALREADY_STARTED) {
70 | error = "ALREADY_STARTED";
71 | } else if (errorCode == ADVERTISE_FAILED_INTERNAL_ERROR) {
72 | error = "INTERNAL_ERROR";
73 | }
74 | Log.e(TAG, error);
75 | result.error("Broadcast", error, null);
76 | }
77 | });
78 | } else {
79 | Log.e(TAG, "FEATURE_UNSUPPORTED");
80 | result.error("Broadcast", "FEATURE_UNSUPPORTED", null);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
17 |
21 |
28 |
32 |
36 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/lib/beacon/authorization_status.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Enum class for showing status about authorization.
8 | class AuthorizationStatus {
9 | /// The defined [String] value of the authorization status.
10 | final String value;
11 |
12 | /// This will `true` only if this authorization status suit Android system.
13 | final bool isAndroid;
14 |
15 | /// This will `true` only if this authorization status suit iOS system.
16 | final bool isIOS;
17 |
18 | @visibleForTesting
19 | const AuthorizationStatus.init(
20 | this.value, {
21 | this.isAndroid = false,
22 | this.isIOS = false,
23 | });
24 |
25 | @visibleForTesting
26 | factory AuthorizationStatus.parse(String value) {
27 | switch (value) {
28 | case 'ALLOWED':
29 | return allowed;
30 | case 'ALWAYS':
31 | return always;
32 | case 'WHEN_IN_USE':
33 | return whenInUse;
34 | case 'DENIED':
35 | return denied;
36 | case 'RESTRICTED':
37 | return restricted;
38 | case 'NOT_DETERMINED':
39 | return notDetermined;
40 | }
41 |
42 | throw Exception('invalid authorization status $value');
43 | }
44 |
45 | /// Shows that user allowed the authorization.
46 | ///
47 | /// Only for Android
48 | static const AuthorizationStatus allowed = AuthorizationStatus.init(
49 | 'ALLOWED',
50 | isAndroid: true,
51 | isIOS: false,
52 | );
53 |
54 | /// Shows that user always authorize app.
55 | ///
56 | /// Only for iOS
57 | static const AuthorizationStatus always = AuthorizationStatus.init(
58 | 'ALWAYS',
59 | isAndroid: false,
60 | isIOS: true,
61 | );
62 |
63 | /// Shows that user authorize when in use app.
64 | ///
65 | /// Only for iOS
66 | static const AuthorizationStatus whenInUse = AuthorizationStatus.init(
67 | 'WHEN_IN_USE',
68 | isAndroid: false,
69 | isIOS: true,
70 | );
71 |
72 | /// Shows that user denied authorization request.
73 | static const AuthorizationStatus denied = AuthorizationStatus.init(
74 | 'DENIED',
75 | isAndroid: true,
76 | isIOS: true,
77 | );
78 |
79 | /// Shows that authorization has been restricted by system.
80 | ///
81 | /// Only for iOS
82 | static const AuthorizationStatus restricted = AuthorizationStatus.init(
83 | 'RESTRICTED',
84 | isAndroid: false,
85 | isIOS: true,
86 | );
87 |
88 | /// Shows that authorization has not been determined by user.
89 | ///
90 | static const AuthorizationStatus notDetermined = AuthorizationStatus.init(
91 | 'NOT_DETERMINED',
92 | isAndroid: true,
93 | isIOS: true,
94 | );
95 |
96 | @override
97 | bool operator ==(Object other) =>
98 | identical(this, other) ||
99 | other is AuthorizationStatus &&
100 | runtimeType == other.runtimeType &&
101 | value == other.value &&
102 | isAndroid == other.isAndroid &&
103 | isIOS == other.isIOS;
104 |
105 | @override
106 | int get hashCode => value.hashCode ^ isAndroid.hashCode ^ isIOS.hashCode;
107 |
108 | @override
109 | String toString() {
110 | return value;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/beacon/bluetooth_state.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 Eyro Labs.
2 | // Licensed under Apache License v2.0 that can be
3 | // found in the LICENSE file.
4 |
5 | part of flutter_beacon;
6 |
7 | /// Enum class for showing state about bluetooth.
8 | class BluetoothState {
9 | @visibleForTesting
10 | const BluetoothState.init(
11 | this.value, {
12 | this.isAndroid = true,
13 | this.isIOS = true,
14 | });
15 |
16 | @visibleForTesting
17 | factory BluetoothState.parse(dynamic state) {
18 | switch (state) {
19 | case "STATE_OFF":
20 | return stateOff;
21 | case "STATE_TURNING_OFF":
22 | return stateTurningOff;
23 | case "STATE_ON":
24 | return stateOn;
25 | case "STATE_TURNING_ON":
26 | return stateTurningOn;
27 | case "STATE_UNKNOWN":
28 | return stateUnknown;
29 | case "STATE_RESETTING":
30 | return stateResetting;
31 | case "STATE_UNSUPPORTED":
32 | return stateUnsupported;
33 | case "STATE_UNAUTHORIZED":
34 | return stateUnauthorized;
35 | }
36 |
37 | return stateUnknown;
38 | }
39 |
40 | /// The defined [String] value of the bluetooth state.
41 | final String value;
42 |
43 | /// This will `true` only if this bluetooth state suit Android system.
44 | final bool isAndroid;
45 |
46 | /// This will `true` only if this bluetooth state suit iOS system.
47 | final bool isIOS;
48 |
49 | /// Shows that bluetooth state is off.
50 | static const stateOff = BluetoothState.init(
51 | 'STATE_OFF',
52 | );
53 |
54 | /// Shows that bluetooth state is turning off.
55 | ///
56 | /// Only for Android
57 | static const stateTurningOff = BluetoothState.init(
58 | 'STATE_TURNING_OFF',
59 | isIOS: false,
60 | );
61 |
62 | /// Shows that bluetooth state is on.
63 | static const stateOn = BluetoothState.init(
64 | 'STATE_ON',
65 | );
66 |
67 | /// Shows that bluetooth state is turning on.
68 | ///
69 | /// Only in Android
70 | static const stateTurningOn = BluetoothState.init(
71 | 'STATE_TURNING_ON',
72 | isIOS: false,
73 | );
74 |
75 | /// Shows that bluetooth state is unknown. This is the default.
76 | static const stateUnknown = BluetoothState.init(
77 | 'STATE_UNKNOWN',
78 | );
79 |
80 | /// Shows that bluetooth state is resetting.
81 | ///
82 | /// Only for iOS
83 | static const stateResetting = BluetoothState.init(
84 | 'STATE_RESETTING',
85 | isAndroid: false,
86 | );
87 |
88 | /// Shows that bluetooth state is unsupported.
89 | static const stateUnsupported = BluetoothState.init(
90 | 'STATE_UNSUPPORTED',
91 | );
92 |
93 | /// Shows that bluetooth state is unauthorized.
94 | ///
95 | /// Only for iOS
96 | static const stateUnauthorized = BluetoothState.init(
97 | 'STATE_UNAUTHORIZED',
98 | isAndroid: false,
99 | );
100 |
101 | @override
102 | bool operator ==(Object other) =>
103 | identical(this, other) ||
104 | other is BluetoothState &&
105 | runtimeType == other.runtimeType &&
106 | value == other.value &&
107 | isAndroid == other.isAndroid &&
108 | isIOS == other.isIOS;
109 |
110 | @override
111 | int get hashCode => value.hashCode ^ isAndroid.hashCode ^ isIOS.hashCode;
112 |
113 | @override
114 | String toString() {
115 | return value;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/android/src/main/java/com/flutterbeacon/FlutterPlatform.java:
--------------------------------------------------------------------------------
1 | package com.flutterbeacon;
2 |
3 | import android.Manifest;
4 | import android.annotation.SuppressLint;
5 | import android.app.Activity;
6 | import android.bluetooth.BluetoothAdapter;
7 | import android.bluetooth.BluetoothManager;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.pm.PackageManager;
11 | import android.location.LocationManager;
12 | import android.os.Build;
13 | import android.provider.Settings;
14 |
15 | import androidx.core.app.ActivityCompat;
16 | import androidx.core.content.ContextCompat;
17 |
18 | import org.altbeacon.beacon.BeaconTransmitter;
19 |
20 | import java.lang.ref.WeakReference;
21 |
22 | class FlutterPlatform {
23 | private final WeakReference activityWeakReference;
24 |
25 | FlutterPlatform(Activity activity) {
26 | activityWeakReference = new WeakReference<>(activity);
27 | }
28 |
29 | private Activity getActivity() {
30 | return activityWeakReference.get();
31 | }
32 |
33 | void openLocationSettings() {
34 | Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
35 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
36 | getActivity().startActivity(intent);
37 | }
38 |
39 | void openBluetoothSettings() {
40 | Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
41 | getActivity().startActivityForResult(intent, FlutterBeaconPlugin.REQUEST_CODE_BLUETOOTH);
42 | }
43 |
44 | void requestAuthorization() {
45 | ActivityCompat.requestPermissions(getActivity(), new String[]{
46 | Manifest.permission.ACCESS_COARSE_LOCATION,
47 | Manifest.permission.ACCESS_FINE_LOCATION
48 | }, FlutterBeaconPlugin.REQUEST_CODE_LOCATION);
49 | }
50 |
51 | boolean checkLocationServicesPermission() {
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
53 | return ContextCompat.checkSelfPermission(getActivity(),
54 | Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
55 | }
56 |
57 | return true;
58 | }
59 |
60 | boolean checkLocationServicesIfEnabled() {
61 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
62 | LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
63 | return locationManager != null && locationManager.isLocationEnabled();
64 | }
65 |
66 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
67 | int mode = Settings.Secure.getInt(getActivity().getContentResolver(), Settings.Secure.LOCATION_MODE,
68 | Settings.Secure.LOCATION_MODE_OFF);
69 | return (mode != Settings.Secure.LOCATION_MODE_OFF);
70 | }
71 |
72 | return true;
73 | }
74 |
75 | @SuppressLint("MissingPermission")
76 | boolean checkBluetoothIfEnabled() {
77 | BluetoothManager bluetoothManager = (BluetoothManager)
78 | getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
79 | if (bluetoothManager == null) {
80 | throw new RuntimeException("No bluetooth service");
81 | }
82 |
83 | BluetoothAdapter adapter = bluetoothManager.getAdapter();
84 |
85 | return (adapter != null) && (adapter.isEnabled());
86 | }
87 |
88 | boolean isBroadcastSupported() {
89 | return BeaconTransmitter.checkTransmissionSupported(getActivity()) == 0;
90 | }
91 |
92 | boolean shouldShowRequestPermissionRationale(String permission) {
93 | return ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | xmlns:android
11 |
12 | ^$
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | xmlns:.*
22 |
23 | ^$
24 |
25 |
26 | BY_NAME
27 |
28 |
29 |
30 |
31 |
32 |
33 | .*:id
34 |
35 | http://schemas.android.com/apk/res/android
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | .*:name
45 |
46 | http://schemas.android.com/apk/res/android
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | name
56 |
57 | ^$
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | style
67 |
68 | ^$
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | .*
78 |
79 | ^$
80 |
81 |
82 | BY_NAME
83 |
84 |
85 |
86 |
87 |
88 |
89 | .*
90 |
91 | http://schemas.android.com/apk/res/android
92 |
93 |
94 | ANDROID_ATTRIBUTE_ORDER
95 |
96 |
97 |
98 |
99 |
100 |
101 | .*
102 |
103 | .*
104 |
105 |
106 | BY_NAME
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/android/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | xmlns:android
11 |
12 | ^$
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | xmlns:.*
22 |
23 | ^$
24 |
25 |
26 | BY_NAME
27 |
28 |
29 |
30 |
31 |
32 |
33 | .*:id
34 |
35 | http://schemas.android.com/apk/res/android
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | .*:name
45 |
46 | http://schemas.android.com/apk/res/android
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | name
56 |
57 | ^$
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | style
67 |
68 | ^$
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | .*
78 |
79 | ^$
80 |
81 |
82 | BY_NAME
83 |
84 |
85 |
86 |
87 |
88 |
89 | .*
90 |
91 | http://schemas.android.com/apk/res/android
92 |
93 |
94 | ANDROID_ATTRIBUTE_ORDER
95 |
96 |
97 |
98 |
99 |
100 |
101 | .*
102 |
103 | .*
104 |
105 |
106 | BY_NAME
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/android/src/main/java/com/flutterbeacon/FlutterBeaconUtils.java:
--------------------------------------------------------------------------------
1 | package com.flutterbeacon;
2 |
3 | import android.util.Log;
4 |
5 | import org.altbeacon.beacon.Beacon;
6 | import org.altbeacon.beacon.Identifier;
7 | import org.altbeacon.beacon.MonitorNotifier;
8 | import org.altbeacon.beacon.Region;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collections;
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.Locale;
15 | import java.util.Map;
16 |
17 | class FlutterBeaconUtils {
18 | static String parseState(int state) {
19 | return state == MonitorNotifier.INSIDE ? "INSIDE" : state == MonitorNotifier.OUTSIDE ? "OUTSIDE" : "UNKNOWN";
20 | }
21 |
22 | static List