Ionic App is crashing with Ngrx and ngx-socket-io - android

I'm working in an Ionic App with angular and socket IO (also I'm using ngrx), but I have a problem that the socket stops when the screen is inactive.
The fail process is this:
First you enter the app, so the socket connects. The socket connects only if my redux state has a token, in other case, the socket will not has to connect
Then, imagine that you left the app executing and your phone automatically locks the screen, so the app changes to an "pause" state
After 10 minutes on the pause state, you unlock your phone which causes that the app enter in a resume state and then is when the socket makes crash the whole app an it simply closes
The socket works correctly
I know is the socket becouse I tried removing just some lines of my socket service and the app are not closing. If I just wait 7 or 8 or 5 minutes or less to unlock the phone, the app won't crash. The crash only happens after 10 minutes with the screen locked
This is my ngx-socket-io configuration
const config: SocketIoConfig = { url: 'http://localhost:5000', options: { transports: ["websocket", "xhr-polling", "jsonp-polling"], autoConnect: false } };
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(),
AppRoutingModule,
StoreModule.forRoot(appReducers),
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production}),
EffectsModule.forRoot(effectsArray),
SocketIoModule.forRoot(config),
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ],
bootstrap: [AppComponent],
})
export class AppModule {}
And this is my app.component.ts
constructor(public store: Store<AppState>, public websocketService: WebsocketService, public appStatusService: AppStatusService, public platform: Platform) { }
ngOnInit() {
this.store.select('session').pipe(filter(session => session !== null)).subscribe(session => {
// IF I REMOVE THIS CONDITION, THE APP WON'T CRASH
if (session.currentSession.token === null) {
// DISCONNECT IF WAS CONNECTED
this.websocketService.disconnectSocket();
} else {
// CONNECT
this.websocketService.connectSocket();
}
});
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.platform.pause.subscribe(e => { this.appStatusService.setStatus(false); });
this.platform.resume.subscribe(e => { this.appStatusService.setStatus(true); });
});
}
This is my webSocket Service
export class WebsocketService {
socketConnected = false;
socketStatus:boolean;
constructor(private socket: Socket, public http: HttpClient, public apiConfigService: ApiConfigService, public authService: AuthService, public platform: Platform) {
this.checkStatus();
}
async connectSocket() {
const data = await this.socketCredentials();
if (data !== null && data !== undefined) {
this.socket.ioSocket.io.opts.query = { sessionUUID: data.sessionUUID, channelUUID: data.channelUUID } ;
this.socketConnected = true;
this.socket.connect();
this.socket.emit( 'JOIN_ROOM', {channelID: data.channelUUID } );
}
}
disconnectSocket() {
if (this.socketConnected === true) { this.socket.disconnect(); this.socketConnected = false; }
}
checkStatus() {
this.socket.on('connect', () => { console.log('SOCKET CONNECTED'); });
this.socket.on('disconnect', () => { console.log('SOCKET DISCONNECTED'); });
}
socketCredentials(): Promise<any> {
// I need to get some credentials to connect the socket. Only can connect to my server if I have this credentials
return new Promise(resolve => {
this.http.get('http://localhost:3000/socket/auth').toPromise().then(response => { resolve(response); });
});
}
}

Related

Connecting 2 arduinos via Bluetooth to the same Android flutter app

I want to connect 2 Arduino to the same mobile app using BLE I have the code for one Arduino connection how to manage it so I can have two Arduino connected
is it possible to connect two Arduinos with BLE to the same app?
Or should I find another alternative
void _connectBLE() {
setState(() {
temperatureStr = 'Loading';
});
_disconnect();
_subscription = _ble.scanForDevices(
withServices: [],
scanMode: ScanMode.lowLatency,
requireLocationServicesEnabled: true).listen((device) {
if (device.name == 'Arduino3') {
print('NiclaSenseME found!');
_connection = _ble
.connectToDevice(
id: device.id,
)
.listen((connectionState) async {
// Handle connection state updates
print('connection state:');
print(connectionState.connectionState);
if (connectionState.connectionState ==
DeviceConnectionState.connected) {
Timer.periodic(Duration(milliseconds: 5), (timer) async{
final characteristic = QualifiedCharacteristic(
serviceId: Uuid.parse("181A"),
characteristicId: Uuid.parse("2A6E"),
deviceId: device.id);
final response = await _ble.readCharacteristic(characteristic);
print(response);
setState(() {
temperature = fromBytesToInt32(response[0],response[1],response[2],response[3]);
print(temperature);
temperatureStr = temperature.toString();
});
});
_disconnect();
print('disconnected');
}
}, onError: (dynamic error) {
// Handle a possible error
print(error.toString());
});
}
}, onError: (error) {
print('error!');
print(error.toString());
});
}

React PWA detect new content on iOS is not working as expected

I use CRA PWA and add toast that's show when onupdatefound and onstatechange. it's working well in android and pc but in iOS it's not shown and content not refresh till close tab and open it again.
I searching long time and not found any good answer for this issue.
I have ServiceWorkerWrapper.ts
import React, { FC, useEffect } from 'react';
import { Snackbar, Button } from '#material-ui/core';
import * as serviceWorker from '../serviceWorkerRegistration';
const ServiceWorkerWrapper: FC = () => {
const [showReload, setShowReload] = React.useState(false);
const [counter, setCounter] = React.useState(0);
React.useEffect(() => {
let timer:any;
if (counter >= 0 && showReload) {
setTimeout(() => setCounter(counter - 1), 1000)
} else if (showReload) {
reloadPage();
}
return () => clearTimeout(timer);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [counter]);
const onSWUpdate = (registration: ServiceWorkerRegistration) => {
if (registration && registration.waiting) {
setShowReload(true);
setCounter(2)
} else {
setShowReload(false);
}
};
useEffect(() => {
serviceWorker.register({ onUpdate: onSWUpdate });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const reloadPage = () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.getRegistration()
.then((reg:any) => {
reg.waiting.postMessage({ type: 'SKIP_WAITING' });
window.location.reload();
})
.catch((err) => console.log('Could not get registration: ', err));
}
};
return (
<Snackbar
open={showReload}
message="A new version is available!"
onClick={reloadPage}
ContentProps={{
className: "reload-snackbar"
}}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
action={
<Button
color="inherit"
size="small"
onClick={reloadPage}
>
Reload{showReload ? ` (${counter + 1})`:''}
</Button>
}
/>
);
}
export default ServiceWorkerWrapper;
serviceWorkerRegistration.ts
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://cra.link/PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);
type Config = {
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://cra.link/PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
if (navigator.vendor === 'Apple Computer, Inc.') {
console.log('Safari!!!!');
if (registration.waiting) {
if (config && config.onUpdate) {
config.onUpdate(registration);
}
}
}
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log('No internet connection found. App is running in offline mode.');
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
});
}
}
service-worker.ts
/// <reference lib="webworker" />
/* eslint-disable no-restricted-globals */
// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
// for the list of available Workbox modules, or add any other
// code you'd like.
// You can also remove this file if you'd prefer not to use a
// service worker, and the Workbox build step will be skipped.
import { clientsClaim } from 'workbox-core';
import { ExpirationPlugin } from 'workbox-expiration';
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
declare const self: ServiceWorkerGlobalScope;
clientsClaim();
// Precache all of the assets generated by your build process.
// Their URLs are injected into the manifest variable below.
// This variable must be present somewhere in your service worker file,
// even if you decide not to use precaching. See https://cra.link/PWA
precacheAndRoute(self.__WB_MANIFEST);
// Set up App Shell-style routing, so that all navigation requests
// are fulfilled with your index.html shell. Learn more at
// https://developers.google.com/web/fundamentals/architecture/app-shell
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
registerRoute(
// Return false to exempt requests from being fulfilled by index.html.
({ request, url }: { request: Request; url: URL }) => {
// If this isn't a navigation, skip.
if (request.mode !== 'navigate') {
return false;
}
// If this is a URL that starts with /_, skip.
if (url.pathname.startsWith('/_')) {
return false;
}
// If this looks like a URL for a resource, because it contains
// a file extension, skip.
if (url.pathname.match(fileExtensionRegexp)) {
return false;
}
// Return true to signal that we want to use the handler.
return true;
},
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
);
// An example runtime caching route for requests that aren't handled by the
// precache, in this case same-origin .png requests like those from in public/
registerRoute(
// Add in any other file extensions or routing criteria as needed.
({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'),
// Customize this strategy as needed, e.g., by changing to CacheFirst.
new StaleWhileRevalidate({
cacheName: 'images',
plugins: [
// Ensure that once this runtime cache reaches a maximum size the
// least-recently used images are removed.
new ExpirationPlugin({ maxEntries: 50 }),
],
})
);
// This allows the web app to trigger skipWaiting via
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
// Any other custom service worker logic can go here.

Capacitor - Not receiving push notifications in Ionic + Angular app

I've started moving on capacitor. After reading https://capacitorjs.com/docs/cordova/known-incompatible-plugins I found that capacitor doesn't support some cordova plugins.
I'm using cordova-plugin-fcm-with-dependecy-updated for android and cordova-plugin-fcm for iOS in my app for push notifications but capacitor doesn’t support these plugins so I used capacitor native approach guided in https://capacitorjs.com/docs/apis/push-notifications#addlistener.
The native approach is not throwing any error and I am able to get registered token as well but I am not receiving push notifications on registered device.
I also tried https://www.npmjs.com/package/capacitor-fcm but fcm.getToken() is returning null.
capacitor.config.json
"plugins": {
"PushNotifications": {
"presentationOptions": [
"badge",
"sound",
"alert"
]
}
}
app.ts
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private fcmService: FcmService
) {
this.initializeApp();
}
ngOnInit() {}
initializeApp() {
this.platform.ready().then(() => {
setTimeout(() => {
this.splashScreen.hide();
}, 300);
this.fcmService.initPush();
});
}
}
fcm.service.ts
import { Injectable } from '#angular/core';
import {
Plugins,
PushNotification,
PushNotificationToken,
PushNotificationActionPerformed,
Capacitor
} from '#capacitor/core';
import { Router } from '#angular/router';
const { PushNotifications, Modals } = Plugins;
import { FCM } from '#capacitor-community/fcm';
const fcm = new FCM();
const { FCMPlugin } = Plugins;
#Injectable({
providedIn: 'root'
})
export class FcmService {
constructor(
private router: Router) { }
initPush() {
alert('Capacitor platform' + Capacitor.platform);
if (Capacitor.platform !== 'web') {
this.registerPush();
}
}
private registerPush() {
PushNotifications.requestPermission().then((permission) => {
if (permission.granted) {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
alert('No permission for push granted');
}
});
PushNotifications.addListener(
'registration',
(token: PushNotificationToken) => {
alert('APN token: ' + JSON.stringify(token));
fcm.getToken().then((r) => {
alert(`FCM Token: ${r.token}`); //---- showing null.
}).catch((err) => {
alert(`FCM Token ERROR: ${JSON.stringify(err)}`);
});
}
);
PushNotifications.addListener('registrationError', (error: any) => {
alert('Registration Error: ' + JSON.stringify(error));
});
PushNotifications.addListener(
'pushNotificationReceived',
async (notification: PushNotification) => {
Modals.alert({
title: notification.title,
message: notification.body
})
}
);
PushNotifications.addListener(
'pushNotificationActionPerformed',
async (notification: PushNotificationActionPerformed) => {
alert('Action performed: ' + JSON.stringify(notification.notification));
}
);
}
}
Is there anything I am missing or I need to add extra configurations to receive push notifications ?
You added SHA certificate fingerprints in your firebase project and update google service file ?

Bluetooth background scanning not working when the app is background in cordova application

I am initializing the blueeothle and peripheral using the foll code:-
bluetoothle.initialize(function initializeResult(result) {
console.log(result);
}, {
request: true,
statusReceiver: true,
restoreKey: "bluetoothleplugin",
});
bluetoothle.initializePeripheral(
function initializeResult(result) {
console.log("initialize peripheral");
console.log(result);
},
function error(result) {
console.log("init peripheral error");
console.log(result);
},
{
request: true,
restoreKey: "bluetoothleplugin",
}
);
and I started the scan using the foll options:-
bluetoothle.startScan(
(result: BluetoothScanResult) => {
console.log("result in searching");
// console.log(result);
if (result.name) {
bluetoothresult.push(result);
resulllt.push(result);
bluetoothresultconst.push(result);
resullltconst.push(result);
}
},
function startScanErrorCallback(err) {
console.log("printing err");
console.log(err);
},
{ serviceUuids: [],allowDuplicates:true }
);
setTimeout(() => {
bluetoothle.stopScan(
(result) => {
console.log("stopping the scanning");
console.log(bluetoothresult);
if (bluetoothresult.length != 0) {
console.log("got result length is more than zero");
}
},
function stopScanErrorCallback(result) {
console.log("came error in stopping the scanning ");
console.log(result);
}
);
}, 40000);
I am getting the scan results fine but when i moved the application to background using the following code:-
cordova.plugins.backgroundMode.moveToBackground();
i was getting empty results for the scan .Ive kept the interval for scan as 60000ms and 40000ms timeout for stopping
but immediately when the app is made to run in foreground scan results were fine.
Note:-I am cheking the applicaiton in a Android 9 device ive even added permission for foreground service in manifest.xml of the cordova and plugin.xml also

I using cordova-plugin-ibeacon but not working(does'nt find beacons in android)

here is code
beacon-provider.ts >>
initialise(): any {
let promise = new Promise((resolve, reject) => {
if (this.platform.is('cordova')) {
IBeacon.enableBluetooth();
this.delegate = IBeacon.Delegate();
this.delegate.didRangeBeaconsInRegion()
.subscribe(
data => {
this.events.publish('didRangeBeaconsInRegion', data);
},
error => console.error()
);
this.region = IBeacon.BeaconRegion('deskBeacon', '24DDF411-8CF1-440C-87CD-E368DAF9C93E');
IBeacon.startRangingBeaconsInRegion(this.region)
.then(
() => {
resolve(true);
},
error => {
console.error('Failed to begin monitoring: ', error);
resolve(false);
}
);
} else {
console.error("This application needs to be running on a device");
resolve(false);
}
});
return promise;
}
}
home.ts >>
export class HomePage {
beacons: BeaconModel[] = [];
zone: any;
constructor(public navCtrl: NavController, public platform: Platform, public beaconProvider: BeaconProvider, public events: Events) {
this.zone = new NgZone({ enableLongStackTrace: false });
}
ionViewDidLoad() {
this.platform.ready().then(() => {
this.beaconProvider.initialise().then((isInitialised) => {
if (isInitialised) {
this.listenToBeaconEvents();
}
});
});
}
listenToBeaconEvents() {
this.events.subscribe('didRangeBeaconsInRegion', (data) => {
this.zone.run(() => {
this.beacons = [];
let beaconList = data.beacons;
beaconList.forEach((beacon) => {
let beaconObject = new BeaconModel(beacon);
this.beacons.push(beaconObject);
});
});
});
}
}
In this code, the result of alert(JSON.stringify(data)) is:
{"eventType":"didRangeBeaconslnRegion","region":{"identifier":"desk beacon","uuid":"24DDF411-8CF1-440C-87CD-E368DAF9C93E","typeName":"BeaconRegion"}, "beacons":[]}
The field data.beacons is empty.
What is the problem?
one more question i try BLE-central plugin first but,
when i was using BLE-central plugin i get signal but it was not given to me major , minor value if i get this value from advertising ?
There are lots of things that might cause this behavior:
Verify that Bluetooth is on
Verify that your app has been granted runtime location permissions needed to detect Bluetooth devices. Go to Settings -> Apps -> [Your app name] -> Permissions, and make sure you see a Location entry with the switch turned on.
Verify using an off-the-shelf detector app that your beacon actually is transmitting the identifier you expect. Try my Locate app here: https://play.google.com/store/apps/details?id=com.radiusnetworks.locate&hl=en

Categories

Resources