Q: Notify and write to Gatt Characteristic - ios

I'm developing an application using react-native. I need to read and write to ble devices. For this I've chosen the react-native-ble-plx library. I'm supposed to notify my characteristic and then write to it packages of 20 bytes. My device is supposed to respond with either a success value or an error (including invalid command). The problem is that my device is not doing anything and i get no response. My code looks like this:
device.monitorCharacteristicForService('service_id', 'char_id', (error, characteristic) => {
if (error) {
console.log(error);
}
else {
console.log(characteristic.value)
}
})
device.writeCharacteristicWithResponseForService('service_id', 'char_id', 'base64firstval')
.then(resp => {
device.writeCharacteristicWithResponseForService('service_id', 'char_id', 'base64secondval')
.then(resp => console.log(resp))
.catch(err => console.log(err))
})
.catch(err => console.log(err))
I successfully connect to the device, read from it. My written command comes from the server so i'm 100% its correct. I've encoded it to base64 before sending it.
Both my promises are resolved so both transfers are made to the device but i get no response from the monitor. After a wile i get
Disconnection from 'device_id' failed: The specified device has disconnected from
us.
and that is because after 5 seconds of no activity my device disconnects itself.

Related

how do I debug push notifications for iOS with Firebase

Trying to get my push notifications working on iOS, starting with my own iOS device
I am able to find my token in Angular, send it to my python backend and store it in a database.
If I go to Compose notification in firebase:
https://console.firebase.google.com/project//notification/compose
I'm able to create the campaign and receive my notification on my phone. However if I hit 'Send test message', enter (or check) my FCM token from the database and hit 'Test' There is no result.
So I am doubting my method to receive my token / if the token is correct.
I'm using Angular, and in my service I'm calling:
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push registration success, token: ' + token.value);
this.tokenvalue = token.value
this.LogOn(username, password, this.tokenvalue)
}); }
Its part of my login form, every time someone logs in the token gets retrieved in case its there:
import { PushNotifications, Token } from '#capacitor/push-notifications';
import { Capacitor } from '#capacitor/core';
(....)
onSubmit(): void {
const { username, password } = this.form;
const isPushNotificationsAvailable = Capacitor.isPluginAvailable('PushNotifications');
if (isPushNotificationsAvailable) {
PushNotifications.requestPermissions().then(result => {
if (result.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
this.tokenvalue = ""
this.LogOn(username, password, this.tokenvalue)
}
});
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push registration success, token: ' + token.value);
this.tokenvalue = token.value
this.LogOn(username, password, this.tokenvalue)
}); }
else {
this.tokenvalue = ""
this.LogOn(username, password, this.tokenvalue)
}
}
The actual token I'm now trying looks like this:
5BA41427198D463847....................80585EAFC3C2670226E22C082A
The 20 dots also represent actual characters like the other ones around it. It's 64 characters in total.
Hope you can help me, am I doing something wrong here? Do I miss a setting somewhere?
Fixed it eventually by going through this article:
https://capacitorjs.com/docs/guides/push-notifications-firebase
Lots of steps I already executed, but missed some changes in files available in Xcode. This changed the actual ID what was printed in the angular application to something that looks like this:
dz0yFZnpH0DkvTntwzrlx-:APA91bG................................................................................JYuH0-7yGReyaqQQUyRmObSa0Cld9QxEHYW9bjSaZQV0jNQjDHRSx
A 164 characters token that now worked when adding a test message as described in the question. Also the python part worked perfectly in connection to this. Used this one:
https://medium.com/#smbhuin/push-notification-firebase-python-8a65c47d3020
In Angular itself remarkably, no changes were necessary at all.
Happy to have this - for me - tough challenge behind me

React-Native IOS notifications not received: APNS device token not set before retrieving FCM Token

This has been posted before, but nothing on there solves my problem.
I am trying to implement react native notifications using the rnfirebase.io library. I am able to receive notifications on my android, but not IOS. (This is run on a physical iPhone)
app.js code to retrieve FCM and notification:
async function GetFCMToken(){
let fcmtoken = await AsyncStorage.getItem("fcmtoken");
console.log(fcmtoken);
if(!fcmtoken) {
try {
const fcmtoken= await messaging().getToken();
console.log(fcmtoken, "123")
if(fcmtoken){
console.log(fcmtoken, "new token");
await AsyncStorage.setItem("fcmtoken", fcmtoken);
}
} catch (error) {
console.log(error,"error in fcmtoken");
}
}
}
async function GetUserPermission(){
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
GetFCMToken();
}
}
const NotificationListener=()=>{
messaging().subscribeToTopic('ios').then(() => console.log('SUBSCRIBED TO TOPIC IOS'))
messaging().onNotificationOpenedApp(remoteMessage => {
console.log('notification received')
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
});
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log('notification received')
console.log(
'Notification caused app to open from quit state:',
remoteMessage.notification,
);
}
});
messaging().onMessage(async remoteMessage => {
console.log('notification received')
alert('New Notification')
console.log("notification on froground state...",remoteMessage)
})
}
The FCM token is successfully logged. I also subscribe to a topic here, but neither sending notifications via topic or FCM are received. (The topic is received by my android phone which has the same app downloaded, though)
Everything I have tried and verified:
The 'APNs Authentication Key' on the firebase console has the p8
certificate added correctly.
The GoogleService-Info.plist is correctly added
A provisioning file and an app identifier is added to the apple
developer console with the push notification capability enabled
On Xcode signing & capability, Push Notifications is enabled, and on
Background Modes, Remote Notifications and background processing is
enabled.
AppDelegate.m has everything that the rnfirebase.io docs say.. pretty
much everything from there is added correctly.
It is not a wifi problem because I am able to fetch APIs
Also, here is the exact error (this is the only error I get, so i think this is what is causing it to not receive notifications)
[Firebase/Messaging][I-FCM002022] APNS device token not set before retrieving FCM Token for Sender ID 'mysenderid'. Notifications to this FCM Token will not be delivered over APNS.Be sure to re-retrieve the FCM token once the APNS device token is set.

Firebase Cloud Messaging to Android works but iOS fails. How to structure payload for iOS?

I can send test notifications from Firebase console to my app both on iOS and Android. Therefore, my app is set up properly to receive push notifications on both platforms. However, when I use a cloud function to send notifications. Only, notifications on the Android device are received. No notifications show up on the iOS device. I suspect this may be related to the way that I create the payload in my cloud function. Maybe I am missing something for iOS. If you could give me some tips, that would be great.
I checked if the deviceToken for the iOS device is correct and it was correct.
I sent a test message using firebase console to the same deviceToken for the iOS device and the notification was delivered.
Therefore, I concluded my problem may arise from the cloud function I wrote. Thus, I share below the cloud function:
exports.notifToApp = functions.database.
ref(`/memInfo/{memId}/notifChoice/`).onWrite((snap, context) => {
//send only if exists and new notification OR if doesn't exist
if ((snap.before.exists() && (snap.after.val() !== snap.before.val())) || !snap.before.exists()) {
//get notification body
const notificationTitle = snap.after.val().memName;
const notificationText = snap.after.val().notifText;
//get and loop over notification subscribers
return admin.database().ref(`/notifics/${context.params.memId}/notifSubs/`).once("value", subs => {
if (subs.exists()) {
return subs.forEach(sub => {
//payload for notification
const payload = {
"notification":{
"title": notificationTitle,
"body": notificationText,
"sound": "default",
"click-action": "FCM_PLUGIN_ACTIVITY",
"priority": "high"
}
}
//deliver notification
return admin.messaging().sendToDevice(sub.val().deviceToken, payload).catch(e => {console.log(e);});
});
} else { //end: if returned any value
return 0;
}
});// end: get and loop over notification subscribers
} else { //end: send only if exists and new notification OR if doesn't exist
return 0;
}
});
I do not get any error messages. Function completes successfully with status "OK."
I test using two devices: one android and one iOS. Both device tokens are saved correctly in the database for the cloud function to retrieve and use for sending messages.
I see the notification on the Android device running my app. I wish the notification to show up on the iOS device running the same app.
Test message notification sent from the firebase console shows up on both devices correctly.
I realized that sendToDevice() used the legacy version of payload. I used send() in my function to use the newer version. (see answer: stackoverflow)
admin.messaging().send(payload).catch(e => console.log(e));
I changed the payload to include platform specific fields according to the latest guidelines (see firebase docs)
const payload = {
"token": sub.val().deviceToken,
"notification":{"title": notificationTitle,"body": notificationText},
"android": {"notification": {"sound": "default"}},
"apns": {"payload": {"aps": {"sound": "default"}}}
};
Now it works on both platforms.

Read SMS in Ionic 3 for IOS

We have an Ionic app in which we need to read a SMS with a validation code that the user will receive when registering into the app.
We are using this plugin which works perfectly in Android. But does not work on IOS it seems like.
I've also seen this Native plugin but it does not support reading sms I don't think.
This is how we read the sms:
...
declare let SMS: any;
readListSMS() {
let filter = {
box: 'inbox', // 'inbox' (default), 'sent', 'draft'
address: '<phone-number>',
indexFrom: 0, // start from index 0
maxCount: 1, // count of SMS to return each time
read: 0
};
if (SMS) {
SMS.listSMS(filter,
(smss) => {
// Here we have access to those sms
},
error => {
alert('error list sms: ' + error);
}
);
}
}
...
Problem is when building the app for ios it wont read the sms, well actually it doesn't even enter the callback.
From what I have read it does not feel possible, also there is not much info about this subject on the internets!
My questions are:
Is it something to do with ios permissions? If so, any help on this would be nice!
Anybody know of a way of accomplishing this for IOS?

Problems subscribing to a room (socket) with Socket.IO-Client-Swift and Swift, Sails.js on the Server

On Swift, I use
socket.on("test") {data, ack in
print(data)
}
In order to subscribe to a room (socket) on my Sails.js API.
When I broadcast a message from the server, with
sails.sockets.broadcast('test', { text : 'ok' })
the socket.on handler is never called.
However, if I set "log" TRUE to config when connecting my socket.io client from swift, in Socket-IO logs the message arrives.
What's wrong?
Eventually, I found my mistake:
The whole process I did is right:
(The request to join the room is done by the server, with sails.sockets.join)
Wrong thing was using socket.on with the ROOM NAME parameter.
I will explain it better, for others having same problem:
From Swift you should subscribe by making a websocket request to an endpoint on the server that accepts websocket requests (GET, POST, PUT). For example, you can make a POST request, passing in the room name into the body.
socket.emitWithAck("post", [
"room": "testroom",
"url": "/api/v1.0/roomsubscribing"
]).timingOut(after: 0) {data in
print("Server responded with \(data)")
}
On server side, inside the room-subscribing endpoint, you should have the following code:
roomSubscribing: function(req, res) {
if (!req.isSocket) {
return res.badRequest();
}
sails.sockets.join(req, req.params('room'), function(err) {
if (err) {
return res.serverError(err);
}
});
}
When the server want to broadcast some data to subscribers of the "testroom" room, the following code must be used:
sails.sockets.broadcast('testroom', { message: 'testmessage' }
Now on the swift's side you must use:
socket.on("message") { data, ack in
print(data)
}
in order to get the message handler to work. I thought you should use room name, instead you should use the KEY of the KEY/VALUE entry you used in your server when you broadcasted the data (in this case, "message").
I only have a small amount of experience with sockets, but in case nobody else answers...
I think you are missing step one of the three step socket process:
A client sends a message to the server asking to subscribe to a particular room.
The client sets up a socket.on to handle particular events from that room.
The server broadcasts an event in a particular room. All subscribers/clients with a .on for that particular event will react.
I could be wrong, but it sounds from your description like you missed step one. Your client has to send a message with io.socket, something like here, then your server has to use the socket request to have them join the room, something like in the example here.
(the presence of log data without the socket.on firing would seem to confirm that the event was broadcast in the room, but that client was not subscribed)
Good luck!

Resources