EddyVerbruggen / nativescript-local-notifications

:mailbox: NativeScript plugin to easily schedule local notifications
MIT License
162 stars 57 forks source link

No sound, no notification, only listed in notifications PT2 #134

Open caiusCitiriga opened 5 years ago

caiusCitiriga commented 5 years ago

Hi Eddy! Sorry for coming back on this issue, but unfortunately it seems to be back...

Although the issue here seems to be kinda "strange" I'll try to provide as many details as I can:

Occurs on: Samsung Galaxy S5 [Android 6.0.1] Issue details: when the application receives a new notification, it just puts it in the notifications bar, as described in the #61. Even if the application is in foreground, no sound is played when the notification comes (and I'm talking about the default sound, no customizations made), and neither is shown the classic "notification dialog" at the top of the screen.

The notifications does arrive even when the app is killed, but still, with no sound and no visual dialog and even if the app is in background, but with the same parts missing.

Instead on my daily phone (OnePlus 5T) with [Android 8.1.0] works like a charm. Only when the app is in foreground

But if in background, or killed, no notifications are listed. And no sounds are played. Well... sometimes. That's why I said that it was strange...

If it can help I list here my package json deps and versions of TNS:

{
    "nativescript": {
        "id": "com.tns.debug.app.debug",
        "tns-android": {
            "version": "5.1.0"
        },
        "tns-ios": {
            "version": "5.1.0"
        }
    },
    "description": "TNS Debug App",
    "license": "SEE LICENSE IN <your-license-filename>",
    "repository": "<fill-your-repository-here>",
    "dependencies": {
        "@angular/animations": "~7.1.0",
        "@angular/common": "~7.1.0",
        "@angular/compiler": "~7.1.0",
        "@angular/core": "~7.1.0",
        "@angular/forms": "~7.1.0",
        "@angular/http": "~7.1.0",
        "@angular/platform-browser": "~7.1.0",
        "@angular/platform-browser-dynamic": "~7.1.0",
        "@angular/router": "~7.1.0",
        "nativescript-angular": "~7.1.0",
        "nativescript-background-geolocation-lt": "^1.9.1",
        "nativescript-google-maps-sdk": "^2.6.1",
        "nativescript-local-notifications": "^3.1.0",
        "nativescript-plugin-firebase": "^7.6.1",
        "nativescript-theme-core": "~1.0.4",
        "nativescript-toast": "^1.4.6",
        "nativescript-uuid": "0.0.1",
        "randomstring": "^1.1.5",
        "reflect-metadata": "~0.1.8",
        "rxjs": "~6.3.0",
        "tns-core-modules": "~5.1.0",
        "zone.js": "^0.8.26"
    },
    "devDependencies": {
        "@angular/compiler-cli": "~7.1.0",
        "@nativescript/schematics": "~0.5.0",
        "@ngtools/webpack": "~7.1.0",
        "@types/randomstring": "^1.1.6",
        "nativescript-dev-typescript": "~0.7.0",
        "nativescript-dev-webpack": "~0.19.0"
    },
    "readme": "NativeScript Application"
}

Hope you can help me :)

And by the way, as always, awesome work! We all greatly appreciate what you are doing ❤️

EddyVerbruggen commented 5 years ago

Hi, thanks for the kind words!

The only thing I can think of is making sure you add forceShowWhenInForeground: true to the plugin params (see the readme for details).

If that doesn't help, can you share a repo showing the issue (or does the demo app in this repo behave in a similar way)?

Thx

caiusCitiriga commented 5 years ago

Hey, thank you for your answer.

So, the forceShowWhenInForeground: true was already set. The thing that worries me the most is the Android 6.0.1 "issue", more than the sporadic 8.1.0 one. Even though it should not happen (but here I wonder if I didn't do something wrong on my side. It's actually really strange that works "sometimes")

Plus, if it can help I'm working with the nativescript-background-geolocation-lt plugin.

Home component code

Deals with the actual notification

import * as firebase from 'nativescript-plugin-firebase';

import { Component } from "@angular/core";

import { Message } from 'nativescript-plugin-firebase';
import { LocalNotifications } from "nativescript-local-notifications";

import { GeoTrackingService } from '~/app/services/geotracking.service';

@Component({
    selector: "ns-app",
    moduleId: module.id,
    templateUrl: "./app.component.html",
})
export class AppComponent {
    public constructor(
        private readonly geotrackSvc: GeoTrackingService
    ) { }

    public ngOnInit(): void {
        firebase.init({
            onPushTokenReceivedCallback: token => {
                this.geotrackSvc.deviceFCMToken = token;
                this.geotrackSvc.registerDevice();
            },
            onMessageReceivedCallback: (message: Message) => {
                console.log(message);

                LocalNotifications.schedule([{
                    body: message.body,
                    title: message.title || 'New notification',
                    at: new Date(new Date().getTime() + (1 * 1000)),
                    forceShowWhenInForeground: true,

                }]);
            }
        }).then(() => {
            console.log('===| Firebase successfully initialized |===');
            this.geotrackSvc.$geolocationStarted.subscribe(res => {
                firebase.getCurrentPushToken().then(currrentToken => {
                    this.geotrackSvc.deviceFCMToken = currrentToken;
                    this.geotrackSvc.registerDevice();
                });
            });
        }).catch(err => {
            console.log('===| ERROR |===');
            console.log('There was an error initializing firebase');
            console.log(err);
        });
    }
}

GeoTracking service

Deals with the GPS and updates postions

export class GeoTrackingService {

    private _deviceUID: string;
    private _deviceFCMToken: string;
    public _location = { lng: 0, lat: 0 };
    private _user = 'myActualUserUID';
    private _$geolocationStarted = new Subject<boolean>();
    private _actualBackendEndpoint = 'my-actual-endpoint';

    public constructor(
        private readonly http: HttpClient
    ) {
        this._deviceUID = deviceUUID.getUUID();
        this.configureBackgroundGeolocation();

        // this._$geolocationStarted.subscribe(() => this.registerHadlessTask());
    }

    public get deviceFCMToken(): string {
        return this._deviceFCMToken;
    }

    public get location(): { lng: number; lat: number } {
        return this._location;
    }

    public get userUID(): string {
        return this._user;
    }

    public set deviceFCMToken(token: string) {
        this._deviceFCMToken = token;
    }

    public get $geolocationStarted(): Observable<boolean> {
        return this._$geolocationStarted;
    }

    public refreshFCMToken(): void {
        console.log('Refreshing FCM token');
        this.http.put(`${this._actualBackendEndpoint}devices/user/${this._user}/device/${this._deviceUID}/fcm-token`, { fcmToken: this.deviceFCMToken })
            .subscribe((res: any) => {
                console.log('===| TOKEN REGISTRATION RESPONSE |===');
                console.log(res);
            });
    }

    public registerDevice(): void {
        console.log('Starting device registration');

        this.http.get(`${this._actualBackendEndpoint}devices/user/${this._user}`)
            .pipe(
                filter((devices: { status: number; data: any }) => {
                    if (devices.status !== 200) {
                        Toast.makeText('There was an error getting the user devices');
                        return false;
                    }

                    if (devices.data.find(d => d.deviceUid === this._deviceUID)) {
                        console.log('Device already registered. Skipping');

                        if (!!this.deviceFCMToken) {
                            this.refreshFCMToken();
                        }
                        return false;
                    }

                    console.log('Device not registered yet. Proceeding with reg.');
                    return true;
                }),
                switchMap(() => this.http.post(`${this._actualBackendEndpoint}devices/user/${this._user}`, {
                    deviceUid: this._deviceUID,
                    fcmToken: this.deviceFCMToken,
                    lastLocation: {
                        type: "Point",
                        coordinates: [this._location.lng, this._location.lat]
                    }
                })),
                tap((response: { status: number; data: any }) => {
                    if (!response.data) {
                        Toast.makeText('There was an error registering the device');
                        return;
                    }

                    console.log('Registered successfully');
                    console.log(response.data);
                })
            ).subscribe()
    }

    private configureBackgroundGeolocation(): void {
        BackgroundGeolocation.ready({
            debug: true,
            reset: true, // issue tmp fix when navigating back from another app to this (?)

            autoSync: true,
            startOnBoot: true,
            desiredAccuracy: 0,
            distanceFilter: 10,
            stationaryRadius: 20,
            enableHeadless: false,
            stopOnTerminate: false,
            foregroundService: true,
            forceReloadOnBoot: true,
            activityRecognitionInterval: 5000,

            method: 'PUT',
            httpRootProperty: 'location',
            url: `${this._actualBackendEndpoint}devices/user/${this._user}/device/${this._deviceUID}/location`,

            notificationTitle: 'Shelly',
            notificationText: 'Servizio di notifica',
            notificationPriority: BackgroundGeolocation.NOTIFICATION_PRIORITY_HIGH,
        }, (state) => {
            // 3. Plugin is now ready to use.
            if (!state.enabled) {
                BackgroundGeolocation.start();
            }
            this._$geolocationStarted.next(true);
        });
    }

}

export interface IOnLocationHeadlessEvent {
    event?: string,
    provider?: {
        gps: boolean,
        status: number,
        network: boolean,
        enabled: boolean,
    },
    is_moving: boolean,
    uuid: string,
    timestamp: string,
    odometer: number,
    coords: {
        latitude: number,
        longitude: number,
        accuracy: number,
        speed: number,
        heading: number,
        altitude: number
    },
    activity: {
        type: string,
        confidence: number
    },
    battery: {
        is_charging: boolean,
        level: number
    },
    extras: any
}

Don't pay too much attention to the "beauty" of this code. It's just a proto/POC app. So the definitive one will come next.

But I'd really love for one time to create a production app using these beautiful cutting-edge technologies that I've used just for personal projects until now. Instead of always falling back on Xamarin or native Android.

If you need further details just ask :)

I'd share the full repo, but there's firebase and aws secret stuff on it..

caiusCitiriga commented 5 years ago

Hey @EddyVerbruggen, any news on this? Did you have the chance to look at it? :)

caiusCitiriga commented 5 years ago

LOL this IS strange!

If you send in the notification message the following property:

{
    ...
    android:{
        notification:{
            sound: 'some-unexisting-sound.mp3'
        }
    }
    ...
}

Android will force play the default notification sound! 😂😂😂😂😂😂

Or a cleaner way:

console.log('============| SETTING UP NOTIFICATION AND RINGTONE |============');
        const ringtoneManager = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION);
        setTimeout(() => {
            const notificationBuilder = new android.app.Notification.Builder(application.android.context);

            const notification = notificationBuilder
                .setSmallIcon(ad.resources.getDrawableId('icon'))
                .setContentTitle('Some test notification')
                .setContentText('Done with native builder')
                .setPriority(2)
                .setSound(ringtoneManager)
                .setVibrate([0, 550, 200, 500])
                .setLights(200, 500, 1000)
                .build();

            const notificationManager = application.android.context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);

            console.log('============| SENDING NOTIFICATION |============');
            notificationManager.notify(0, notification);
        }, 5000);

Note that it will work only on Android 7 and below. For newer versions, you have to set up the notification channel too.

andipahlevy commented 4 years ago

Is this plugin can't play custom mp3 audio? android