MacKentoch / react-native-beacons-manager

React-Native library for detecting beacons (iOS and Android)
MIT License
580 stars 318 forks source link

Beacon notification is always showing in Android #152

Open phoenix377 opened 5 years ago

phoenix377 commented 5 years ago

Version

1.4.9

Platform

Android

OS version

android 9

Steps to reproduce

  1. install react-native-beacons-manager
  2. open your app
  3. close your app

Expected behavior

No beacons notification.

Actual behavior

Beacons notification is active all the time even if I close my app or if I don't use 'react-native-beacons-manager' (like 'startMonitoringForRegion') in app's code.

screenshot
iamandiradu commented 5 years ago

While you're scanning, that thing will appear there. You can avoid it by scanning at an interval. (check WhatsApp's live location sharing implementation).

phoenix377 commented 5 years ago

@iamandiradu Issue is that it's appearing though you are not scanning. Beacon notification is active all the time even if I close my app or if I don't use 'react-native-beacons-manager' (like startMonitoringForRegion) in app's code.

iamandiradu commented 5 years ago

I recognize the "Scanning for Beacons" string from @ newoceaninfosys fork. I also made a fork after that fork (double fork?) and implemented a toggle logic for the Beacon Service. I can provide an usage example tomorrow, if it's not too late.

(look at startBeaconService and stopBeaconsService in the sources for Android)

phoenix377 commented 5 years ago

@iamandiradu That will be great if you can provide it tomorrow. Thanks.

iamandiradu commented 5 years ago
componentDidMount() {
    this._beaconsInit();
}

_beaconsInit = async () => {
    // function that checks is Bluetooth and Location services are enabled
    const proximityCapabilities = await this._proximityCapabilities();
    if (this.props.beaconsEnabled && proximityCapabilities) {
        // Beacons listener
        this.beaconEnterListener = Beacons.BeaconsEventEmitter.addListener(
            'regionDidEnter',
            data => this._beaconListener(data));

        if (Platform.OS === 'ios') {
            // iOS cold start listener
            this.beaconMissedListener = Beacons.BeaconsEventEmitter.addListener(
                'onMissedBeacon',
                data => {
                    if (data) {
                        this._beaconListener(data);
                    }
                },
            );
            // iOS on cold start tends to send the beacon event before the JS is loaded, thus 'missing' the beacon
            // I've added in the library a method that stores the beacon data if no listener is attached and send it when getMissedBeacon is called
            Beacons.getMissedBeacon();
        }

        this._startBeaconService();
    } else {
        this.props.disableBeacons();
        this._stopBeaconService();
    }
}

_startBeaconService = (toggled = false) => {
    if (Platform.OS === 'ios') {
        Beacons.allowsBackgroundLocationUpdates(false);
        this._monitorForRegions(false);
        Beacons.startUpdatingLocation();
        // Adds the listener in case the service was toggled and was not initiated on app start
        if (toggled) {
            this.beaconEnterListener = Beacons.BeaconsEventEmitter.addListener(
                'regionDidEnter',
                data => this._beaconListener(data));
        }
    } else {
        // Start the fresh service
        Beacons.addIBeaconsDetection()
            .then(() => Beacons.startBeaconService(toggled))
            .then(() => this._monitorForRegions(false))
            .catch(error => {
                console.warn('Error at Service start: ' + error);
            });
    }
};
_stopBeaconService = (toggled = false) => {
    if (Platform.OS === 'android') {
        this.beaconsServiceDidConnect && this.beaconsServiceDidConnect.remove();
        Beacons.removeIBeaconsDetection().catch(error =>
            console.warn(`Something went wrong during Beacon detection removal: ${error}`),
        );
    } else {
        Beacons.allowsBackgroundLocationUpdates &&
            Beacons.allowsBackgroundLocationUpdates(false);
        Beacons.startUpdatingLocation && Beacons.stopUpdatingLocation();
    }

    this._monitorForRegions(true);
    this.beaconEnterListener && this.beaconEnterListener.remove();
    if (Platform.OS === 'android') {
        Beacons.stopBeaconService(toggled)
            .then()
            .catch(error => {
                console.warn('Error at Service stop: ' + error);
            });
    }
};
_beaconListener = data => {
    const detectedBeacon =
        R.filter(beacon => beacon.id === Number(data.identifier), this.props.beacons)[0] ||
        false;
    const detectedBeaconTag = this.props.beaconTags[detectedBeacon.tag];

    console.log(detectedBeacon); /* do something with the detected beacon */
};
_monitorForRegions = (stop = false) => {
    R.forEach(eachRegion => {
        const generatedRegion = {
            identifier: `${eachRegion.id}`,
            uuid: eachRegion.beaconId,
        };
        // Monitor for beacons inside the region
        if (!stop) {
            Beacons.startMonitoringForRegion(generatedRegion)
                .then()
                .catch(error => {
                    console.warn(`Beacons monitoring not started: ${error}`);
                });
        } else {
            Beacons.stopMonitoringForRegion(generatedRegion)
                .then()
                .catch(error => console.warn(`Beacons monitoring not stopped: ${error}`));
        }
    }, this.props.beacons); // an object that contains our registered beacons
    /* 
    "beacons": [
        {
            "id": 1,
            "tag": "tag1",
            "beaconId": "8323fff7-82fa-4e74-a7dd-cc5fe64f7461",
        },
    ],
    "beaconTags": {
            "tag1": {
            "title": "title 1",
            "message": "message 1"
        },
    ]
    */
};

_proximityCapabilities = async () => {
    const bluetoothEnabled = await BluetoothStatus.state();
    const locationEnabled = await SystemSetting.isLocationEnabled();
    return bluetoothEnabled && locationEnabled;
}

What you need in order for that permanent notification to dismiss is to call stopBeaconService() and pass 'true' if the service was active on app launch and toggled later.

This happens because @newoceaninfosys started the notification channel/service in the init function of the library, so I just split it in 2 methods: start and stop. :)

ielonclesio commented 4 years ago

@iamandiradu What version of RN are you using? I am using RN 0.60 and not finding the beacons.

iamandiradu commented 4 years ago

@ielonclesio, also 0.60.