flutter_beacons 0.3.0+3

  • Readme
  • Changelog
  • Example
  • Installing
  • 37

Beacons #

pub package

Flutter plugin to work with beacons.
Supports Android API 16+ and iOS 8+.


  • Automatic permission management
  • Ranging
  • Monitoring (including background)

Supported beacons specifications:

  • iBeacon (iOS & Android)
  • Altbeacon (Android)

Installation #

Add to pubspec.yaml:

  beacons: ^0.3.0

Note: The plugin is written in Swift for iOS.
There is a known issue for integrating swift plugin into Flutter project using the Objective-C template. Follow the instructions from Flutter#16049 to resolve the issue (Cocoapods 1.5+ is mandatory).

Setup specific for Android #

Create a subclass of FlutterApplication:

class App : FlutterApplication() {

    override fun onCreate() {

        // Beacons setup for Android
        BeaconsPlugin.init(this, object : BeaconsPlugin.BackgroundMonitoringCallback {
            override fun onBackgroundMonitoringEvent(event: BackgroundMonitoringEvent): Boolean {
                val intent = Intent(this@App, MainActivity::class.java)
                return true

And register it in android/app/src/main/AndroidManifest.xml:

<manifest ...>

BeaconsPlugin.BackgroundMonitoringCallback is required to react to background monitoring events. The callback will be executed when a monitoring event is detected while the app is running in background. In the snipped above, it will start the Flutter app. It will also allow to receive a callback on the Flutter side. See background monitoring section for more details.

For permission, see below.

Setup specific for iOS #

Nothing. Contrary to the general opinion, you do not need to enable any background mode.

For permission, see below.

Permission #

In order to use beacons related features, apps are required to ask the location permission. It's a two step process:

  1. Declare the permission the app requires in configuration files
  2. Request the permission to the user when app is running (the plugin can handle this automatically)

For iOS

There are two available permissions in iOS: when in use and always.
The latter is required for background monitoring.

For more details about what you can do with each permission, see:

Permission must be declared in ios/Runner/Info.plist:

  <!-- When in use -->
  <string>Reason why app needs location</string>

  <!-- Always -->
  <!-- for iOS 11 + -->
  <string>Reason why app needs location</string>
  <!-- for iOS 9/10 -->
  <string>Reason why app needs location</string>

For Android

There are two available permissions in Android: coarse and fine.
For beacons related features, there are no difference between the two permission.

Permission must be declared in android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <!-- or -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

How-to #

Ranging and monitoring APIs are designed as reactive streams.

  • The first subscription to the stream will start the ranging/monitoring ;
  • The last cancelling (when there are no more subscription) on the stream will stop the ranging/monitoring operation.

Ranging beacons #

  region: new BeaconRegionIBeacon(
    identifier: 'test',
    proximityUUID: '7da11b71-6f6a-4b6d-81c0-8abd031e6113',
  inBackground: false, // continue the ranging operation in background or not, see below
).listen((result) {
  // result contains a list of beacons
  // list can be empty if no matching beacons were found in range

Background ranging

When turned off, ranging will automatically pause when app goes to background and resume when app comes back to foreground. Otherwise it will actively continue in background until the app is terminated by the OS.

Ranging beacons while the app is terminated is not supported by the OS. For this kind of usage, see background monitoring.

Monitoring beacons #

  region: new BeaconRegionIBeacon(
    identifier: 'test',
    proximityUUID: '7da11b71-6f6a-4b6d-81c0-8abd031e6113',
  inBackground: false, // continue the monitoring operation in background or not, see below
).listen((result) {
  // result contains the new monitoring state:
  // - enter
  // - exit

Background monitoring

When turned off, monitoring will automatically pause when app goes to background and resume when app comes back to foreground. Otherwise it will actively continue in background until the app is terminated by the OS.

Once the app has been terminated, the monitoring will continue.
If a monitoring event happens, the OS will start the app in background for several seconds (nothing will be visible for the user). The OS is providing you the opportunity to perform some quick operation, like showing a local notification.

In order to listen to background monitoring events, you can subscribe to a special stream. This stream is passive: it does not start a monitoring operation. You are still required to start it using Beacons.monitoring(inBackground: true).

Because the OS will run the app in background for several seconds only, before terminating it again, the good place to setup the listener is during app startup.

class MyApp extends StatefulWidget {
  MyApp() {
    Beacons.backgroundMonitoringEvents().listen((event) {
      final BackgroundMonitoringEventType type = event.type // didEnterRegion, didExitRegion or didDetermineState
      final BeaconRegion region = event.region // The monitored region associated to the event
      final MonitoringState state = event.state // useful for type = didDetermineState

      // do something quick here to react to the background monitoring event, like showing a notification

  _MyAppState createState() => new _MyAppState();

For testing background monitoring and what result you should expect, read:

Alternatively to starting/stoping monitoring using Beacons.monitoring() stream subscription, you can use the following imperative API:

// Result will be successful if monitoring has started, or contain the reason why it has not (permission denied, etc)
final BeaconsResult result = await Beacons.startMonitoring(
  region: BeaconRegionIBeacon(
    identifier: 'test',
    proximityUUID: 'uuid',
  inBackground: true,

await Beacons.stopMonitoring(
  region: BeaconRegionIBeacon(
    identifier: 'test',
    proximityUUID: 'uuid',

Note that these functions can only start/stop the monitoring.
To receive the associated monitoring events, listen to the stream from Beacons.backgroundMonitoringEvents().

Beacons types #

For every API that requires or return a region or a beacon, you can work with the different types of beacons specs.

Regardless of the beacons specs, each region requires an unique identifier that are used by the engine under the hood to uniquely identify and manage a ranging/monitoring request.


Beacons.ranging(region: BeaconRegion(
    identifier: 'test',
    ids: ['id1', 'id2', 'id3'],
).listen((result) {
  final Beacon beacon = result.beacons.first;


Beacons.ranging(region: BeaconRegionIBeacon(
    identifier: 'test',
    proximityUUID: 'some-uuid',
    minor: 0,
).listen((result) {
  final BeaconIBeacon beacon = BeaconIBeacon.from(result.beacons.first);

Under the hood #

  • iOS uses native iOS CoreLocation
  • Android uses the third-party library android-beacon-library (Apache License 2.0)

Each technology has its own specificities.
The plugin does its best to abstract it and expose a common logic, but for an advanced usage, you would probably still need to familiarize yourself with the native technology.

Beacons plugin development is sponsored by Pointz, a startup that rewards people for spending time at local, brick and mortar businesses. Pointz is proudly based in Birmingham, AL.

Author #

Beacons plugin is developed by Loup, a mobile development studio based in Montreal and Paris.
You can contact us at hello@intheloup.io

License #

Apache License 2.0

[0.3.0] #

  • Fix: Background monitoring on Android
  • New: Settings API
  • New: Imperative start/stop monitoring API
  • Breaking change: Additional plugin configuration required for Android

[0.2.1] #

  • Breaking change: Renamed BeaconRegionIBeacon.wrap() to from()

[0.2.0] #

  • Breaking change: Renamed backgroundMonitoringEvent.name to type (enum)

[0.1.2] #

  • New: Exposed BackgroundMonitoringEvents
  • Breaking change: Renamed MonitoringEvent to MonitoringState

[0.1.1] #

  • Fix: iOS background support

[0.1.0] #

  • New feature: Android support
  • Revamp public API to match new Android support
  • Revamp example

[0.0.2] #

  • Revamp public API
  • New feature: iBeacons monitoring (iOS only)

[0.0.1] - Initial release #

  • New feature: iBeacons ranging (iOS only)


//  Copyright (c) 2018 Loup Inc.
//  Licensed under Apache License v2.0

import 'package:flutter_beacons/flutter_beacons.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_local_notifications/initialization_settings.dart';
import 'package:flutter_local_notifications/notification_details.dart';
import 'package:flutter_local_notifications/platform_specifics/android/initialization_settings_android.dart';
import 'package:flutter_local_notifications/platform_specifics/android/notification_details_android.dart';
import 'package:flutter_local_notifications/platform_specifics/ios/initialization_settings_ios.dart';
import 'package:flutter_local_notifications/platform_specifics/ios/notification_details_ios.dart';

import 'tab_monitoring.dart';
import 'tab_ranging.dart';

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  MyApp() {
    Beacons.loggingEnabled = true;

    int notifId = 0;

    Beacons.backgroundMonitoringEvents().listen((event) {
      FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
          new FlutterLocalNotificationsPlugin();
      InitializationSettingsAndroid initializationSettingsAndroid =
          new InitializationSettingsAndroid('app_icon');
      InitializationSettingsIOS initializationSettingsIOS =
          new InitializationSettingsIOS();
      InitializationSettings initializationSettings =
          new InitializationSettings(
              initializationSettingsAndroid, initializationSettingsIOS);

      NotificationDetailsAndroid androidPlatformChannelSpecifics =
          new NotificationDetailsAndroid('your channel id', 'your channel name',
              'your channel description');
      NotificationDetailsIOS iOSPlatformChannelSpecifics =
          new NotificationDetailsIOS();
      NotificationDetails platformChannelSpecifics = new NotificationDetails(
          androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);

      android: BeaconsSettingsAndroid(
        logs: BeaconsSettingsAndroidLogs.info,

  _MyAppState createState() => new _MyAppState();

class _MyAppState extends State<MyApp> {
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new CupertinoTabScaffold(
        tabBar: new CupertinoTabBar(
          items: <BottomNavigationBarItem>[
            new BottomNavigationBarItem(
              title: new Text('Track'),
              icon: new Icon(Icons.location_searching),
            new BottomNavigationBarItem(
              title: new Text('Monitoring'),
              icon: new Icon(Icons.settings_remote),
            new BottomNavigationBarItem(
              title: new Text('Settings'),
              icon: new Icon(Icons.settings_input_antenna),
        tabBuilder: (BuildContext context, int index) {
          return new CupertinoTabView(
            builder: (BuildContext context) {
              switch (index) {
                case 0:
                  return new RangingTab();
                case 1:
                  return new MonitoringTab();
                  return new Container(
                    child: new Center(
                      child: new Text('TBD'),

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  flutter_beacons: ^0.3.0+3

2. Install it

You can install packages from the command line:

with pub:

$ pub get

with Flutter:

$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:flutter_beacons/flutter_beacons.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Apr 4, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health issues and suggestions

Fix lib/channel/helper.dart. (-25 points)

Analysis of lib/channel/helper.dart failed with 1 error:

line 18 col 7: The argument type 'String' can't be assigned to the parameter type 'DiagnosticsNode'.

Document public APIs. (-0.25 points)

114 out of 117 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Maintenance issues and suggestions

No valid SDK. (-20 points)

The analysis could not detect a valid SDK that can use this package.

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (streams_channel).

Package is getting outdated. (-28.22 points)

The package was last published 66 weeks ago.

The package description is too short. (-17 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.19.0 <3.0.0
flutter 0.0.0
streams_channel ^0.2.1 0.2.3 0.3.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8