I have been trying to use Amazon Pinpoint to run push notification campaign for iOS using the sample app to no avail. For Android, it was successful though. I tried pushing using APNS directly and Amazon SNS, both were successful.
I am suspecting that there are some certification issues relating to iOS. I used this documentation guide to obtain the .p12 certificate to upload to 'Manage - Channel' section of the Pinpoint interface and also for Amazon SNS.
http://docs.aws.amazon.com/mobile-hub/latest/developerguide/ios-appid-setup.html
The devices were detected but the messages weren't delivered to iOS. In the screenshot below, the delivered count is for Android device (2 iOS device, 1 Android).
Any help will be greatly appreciated. Thanks!!
Could this be because your cert is a "dev" or "APNS Sandbox" cert?
If so, sending to APNS Sandbox is not currently supported via the Amazon Pinpoint Console.
To do so using the CLI (or any SDK) is relatively straightforward but requires some shell knowledge.
You'll first want to register your APNS_SANDBOX channel
## Assuming you have your cert and key in the following files
MY_CERT=$(cat my-cert.ct)
MY_KEY=$(cat my-key.pk)
aws pinpoint update-apns-sandbox-channel --apns-sandbox-channel-request Certificate=$MY_CERT,Enabled=true,PrivateKey=$MY_KEY
Then you can send to any address directly using the direct send API
aws pinpoint send-messages --message-request "{
\"Addresses\": {
\"YOUR_SANDBOX_TOKEN_HERE\": {
\"ChannelType\": \"APNS_SANDBOX\"
}
},
\"MessageConfiguration\": {
\"APNSMessage\": {
\"Action\": \"OPEN_APP\",
\"Body\": \"Body of message\",
\"Title\": \"Subject\"
}
}
}"
Related
In Apple Push Notification service (APNs), the server-side developer must choose the environment type (sandbox or production) as the HTTP/2 URL (api.sandbox.push.apple.com or api.push.apple.com). [1]
On the other hand, in Firebase Cloud Messaging (FCM) over APNs, there seems no explicit interface to specify the environment type. [2]
So I guess FCM somehow decide the environment type internally, but I have no idea about how it detects the environment type.
Does anyone have knowledge about it? Any insight would be helpful. Thanks!
Some pre-requisite information
The sandbox environment is always used when the app is built and ran through Xcode in debug, release or profile configurations, or if the app is distributed through development method.
The production environment is used when the app is distributed through App Store Connect (App Store and TestFlight), Ad Hoc and Enterprise methods. See "Distributing Your App for Beta Testing and Releases" for more information.
To find out what distribution mode/ APNs environment is used, you have to read the provisioning profile. On iOS, watchOS and tvOS, it is embedded.mobileprovision, and in macOS or Catalyst, it is embedded.provisionprofile. You cannot read App.entitlements, because that file isn't always available. Instead, embedded.mobileprovision contains a dictionary (in XML format). This is an example of this file I extracted from a test app. It contains, among other things:
<key>Entitlements</key>
<dict>
<key>aps-environment</key>
<string>development</string>
...
If you generate one yourself (archive the Xcode project), you can view the package contents of the xcarchive (/Users/username/Library/Developer/Xcode/Archives/2021-08-28/projectName\ 28-08-2021,\ 08.17.xcarchive/Products/Applications/projectName.app/embedded.mobileprovision), and it is shown nicely in the finder preview.
There is also a comment in the Firebase iOS SDK:
* #param type The type of APNs token. Debug builds should use
* FIRMessagingAPNSTokenTypeSandbox. Alternatively, you can supply
* FIRMessagingAPNSTokenTypeUnknown to have the type automatically
* detected based on your provisioning profile.
Firebase's solution
You could read FIRMessagingTokenManager.m, or read my analysis across different files:
In Firebase iOS SDK, If you pass don't pass a type (sandbox/ production) or explicitly pass FIRMessagingAPNSTokenTypeUnknown, this code runs:
if (type == FIRMessagingAPNSTokenTypeUnknown) {
isSandboxApp = FIRMessagingIsSandboxApp();
}
which is
BOOL FIRMessagingIsSandboxApp(void) {
static BOOL isSandboxApp = YES;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isSandboxApp = !FIRMessagingIsProductionApp();
});
return isSandboxApp;
}
FIRMessagingIsProductionApp is a method that is 119 lines long. What does it do? It almost always defaults to a production app, theres a lot of Firebase specific configuration logic and checking if production if running on iOS simulator, if app is delivered AppStore or TestFlight
Fundamentally it checks embedded.provisionprofile or embedded.mobileprovision (that is how plistMap is generated):
// plistMap is loaded from the provisioning profile in a multi step process.
NSString *apsEnvironment = [plistMap valueForKeyPath:kEntitlementsAPSEnvironmentKey];
if ([apsEnvironment isEqualToString:kAPSEnvironmentDevelopmentValue]) {
return NO;
}
where they reference the following keys inside the provisioning profile:
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
static NSString *const kEntitlementsAPSEnvironmentKey = #"Entitlements.aps-environment";
#else
static NSString *const kEntitlementsAPSEnvironmentKey =
#"Entitlements.com.apple.developer.aps-environment";
#endif
static NSString *const kAPSEnvironmentDevelopmentValue = #"development";
If you're interested in seeing how the provisioning profile is read, read the source file.
Create full path to provisioning profile
Load data from file path
Clean the data (the provisioning profile contains 0 which "halts" the ASCII parser, or value larger than 127, which is invalid.)
Convert Data to String
Scan the string using NSScanner. They do this because the provisioning profile contains a lot more non-xml/ non-plist structure. Look at the example file.
Convert this string back into data.
Convert this data into a dictionary using NSPropertyListSerialization
Look for ProvisionedDevices key, if so, it's a dev profile.
Get environment from dictionary with kEntitlementsAPSEnvironmentKey
How does firebase servers know which endpoint to use?
Finally, once the Firebase iOS SDK knows that a device (and APNs device token) is running in production/ development, it can tell the APNs provider (their server which connects with APNs) to use the correct endpoint, either api.push.apple.com:443 and api.sandbox.push.apple.com:443 aka. api.development.push.apple.com:443 (its just a CNAME pointing to sandbox). This isProduction or isSandbox boolean will probably live with the APNs device token in a Firebase database.
I found the answer on the doc on FIRInstanceIDAPNSTokenType
http://cocoadocs.org/docsets/FirebaseInstanceID/1.0.6/Constants/FIRInstanceIDAPNSTokenType.html
The APNS token type for the app. If the token type is set to UNKNOWN InstanceID will implicitly try to figure out what the actual token type is from the provisioning profile.
Therefore, the answer is "the actual token type is determined by the provisioning profile", maybe by "aps-environment" key.
The FCM token we use for sending the notifications is generated by the SDK using multiple parameters. It contains information about the actual APNS device token, Project ID, Project URL endpoint on Firebase, App Bundle Identifier, etc (You get an invalid token error if you try to use some other token generated from different Firebase configuration). It stands to reason that the FCM token also takes into account the Environment used for compiling the application (DEBUG/RELEASE). Using this information, Firebase should be able to use the corresponding APNS gateways.
I'm trying to add push notifications to my Ionic app using FCM and running into issues with IOS, (android works as intended). Before marking this as a duplicate, Ive tried the solutions from the other similar questions but it didnt help.
In the firebase console I have set the team Id, App id as well as uploded the APNS p5 generated by apple to my console as well.
And finally, the latest plist file to my app's root. From xcode, I can see the certificate has push notifications enabled too and the app asks for that permission for it as well. After that I got the device notification id and tested it via the console as well as the api endpoint but I keep getting the "InvalidApnsCredential" error. I did the steps from few other questions from here but had no luck. I cant seem to get it working, below is a few snippets of my code
this.platform.ready().then(() => {
this.fcmService.getToken().then(resp=>{
this.httpService.sendToken(resp)
.subscribe(res => {
console.log(res)
});
console.log(resp)
});
});
And the body of the api post request
Endpoint: https://fcm.googleapis.com/fcm/send
Body:
{
"notification":{
"title":"Ionic 4 Notification",
"body":"This notification sent from POSTMAN using Firebase HTTP protocol",
"sound":"default",
"click_action":"FCM_PLUGIN_ACTIVITY",
"icon":"fcm_push_icon"
},
"data":{
"landing_page":"second",
"price":"$3,000.00"
},
"to":"IOS_DEVICE_NOTIFICATION_ID",
"priority":"high",
"restricted_package_name":""
}
The code and api endpoint seems correct as it works for Android. Is there anything im missing to get it working?
So, this may not be exactly the answer that youre looking for but, for me everything worked fine after i recreated the app on ios.
Common issues include
- trying to send a notification before the client gives premission
- sending notifications using older IDs (yes they change sometimes)
- package name mismatch between your app and ios app
Following are the reasons of "InvalidApnsCredential":
Maybe bundle id changed [find in code where bundle id name mismatch, change it]
APN keys expired [ update it in firebase console]
Find out the exact error from this link enter link description here that you got.
In my case, I forgot to enter and upload the APNs Authentication Key in the firebase console. Please go to the
Cloud Messaging -> Apple app configuration
Add AuthKey File(.p8), Key Id & Team ID
Check the image below. And it's working fine for me.
Make sure Team ID is added in the SDK setup and configuration.
I have pushed a Phoenix app to Heroku and it is running fine, apart from connecting to a channel from iOS.
Channels over the browser work as expected.
In iOS I am using PhoenixWebSocket, and in dev env, connecting to the local Phoenix app works as expected.
The problem I am getting is when I point the web socket url to the Heroku app I get the following error:
Error Domain=WebSocket Code=301 "Invalid HTTP upgrade" UserInfo={NSLocalizedDescription=Invalid HTTP upgrade}
Looking around for the error message earlier today, I found a post from Chris McCord, I think it was, saying that this error message is a result of the server refusing to upgrade the request.
However, I've looked around Heroku and found that; Websockets functionality is supported for all applications.
So I'm confused as to whether my problem is on the iOS side, or the Heroku side.
I have pushed Chris's example chat application to Heroku, and tried to connect with the demo app that comes with PhoenixWebSocket, but get the same error.
Has anyone else managed to get web socket requests working between iOS and Heroku hosting a Phoenix app?
Would anyone know if there is something differently I need to do with the request in iOS before trying to join the channel? Or, maybe there is something with the Heroku setup relating to web sockets that I've missed?
The url for the request in iOS:
let url = NSURL(string: "ws://app-name-32793.heroku.com/socket/websocket")!
Many thanks to anyone that can help, and please let me know if there's anything else I can supply to help.
Paul
I know this is old but one possible issue is you may need to connect via https/wss. So either
let url = NSURL(string: "wss://app-name-32793.heroku.com/socket/websocket")!
or:
let socket = Socket(domainAndPort: "app-name-32793.heroku.com", path: "socket", transport: "websocket", prot: "https", params: [])
I've set up my mobile service on Azure and uploaded the development certificate with push notification permissions. I'm using mono touch to the get the device token from the app and sending that up with a request. When the item is inserted I want to send a push to the client but in the logs I keep getting this error
{ [Error: 400 - Invalid expression: '568d4f52 615ee9.......
where the expression is my device token. If I go to the table I can see that the device token matches the one generated in the iOS app. I did upgrade the mobile service to the enhanced push but can't find any examples of how to push to a single user. In my code I have
request.execute();
push.apns.send(item.pushNotificationHandle, {
alert : 'testing',
payload: { text1: 'inner text' }
}, {
error: function(error){
console.error(error);
}
});
The docs on the Azure site seem to be getting pretty stale so I've no idea where the error is and how it should be different. Looking at their server reference docs here I'm not sure why this is failing
http://msdn.microsoft.com/en-US/library/azure/jj839711.aspx#send
Does anyone have any experience with this? I have logged out "item.pushNotificationHandle" and it is a string as expected (matches in the table)
Thanks for pointing out the documentation which has not yet been updated.
Please see this documentation for an almost accurate enhanced push version of push.apns: http://dl.windowsazure.com/nodedocs/ApnsService.html
What you can see is that the send method's first member is tags.
To use enhanced push to target a single user, you should add a unique id for that user the user's tags. Then you send the notification to that specific user's tag. (This feature can also be used for sending to a subset group of users.)
I’m trying to sync a Couchbase bucket from the server to an iOS app using the Couchbase Sync Gateway and Couchbase Lite for iOS.
So far I’m working with the "beer-sample" example bucket that comes with Couchbase.
On my Ubuntu 12.04 LTS VM, the Couchbase Sync Gateway is started with this config file:
{
"interface":":4984",
"adminInterface":":4985",
"log":["REST"],
"databases":{
"sync_gateway":{
"server":"http://localhost:8091",
"bucket":"beer-sample",
"sync":`function(doc) {channel(["public"]);}`,
"users": {
"GUEST": {"disabled": false, "admin_channels": ["public"]}
}
}
}
}
My intention is to get it running without worrying about authentication first, therefore the GUEST user.
I’ve also modified some example to make sure the channel assignment is not dependent on the documents, because the sample bucket doesn’t have any channel assignment:
"sync":`function(doc) {channel(["public"]);}`,
I included some code from https://github.com/couchbaselabs/ToDoLite-iOS/blob/master/TodoLite7/CBLSyncManager.m into my own example project, and after a bit of trying the iOS can actually connect to the connector.
The NSLog in line 168 gives me this output:
[1026:60b] SYNCMGR: active=0; status=1; 0/0; (null)
[1026:60b] SYNCMGR: active=1; status=3; 0/0; (null)
[1026:60b] SYNCMGR: active=0; status=2; 0/0; (null)
…and my interpretation of that is that the syncing (of 0 documents) was working successfully.
Why does the Couchbase Sync Gateway not report any documents to Couchbase Lite? I’m obviously missing something. I suspect the channels are not setup correctly.
Any help will be appreciated and if your answer solves my problem, I will accept it.
as this was re-posted from our communities portal, I will close out this issue here with a re-post in response and continued questions should be on our communities portal.
Based on your description of the issue and configuration, you still need to configure your Sync Gateway to let it know there is an existing Couchbase Server bucket it needs to sync from.
This is a recent feature add after our Beta 2; we're currently working on the documentation, which is available interim here: https://github.com/couchbase/sync_gateway/wiki/Bucket-Shadowing
Continued thread can be found here: http://www.couchbase.com/communities/q-and-a/sync-couchbase-lite-through-couchbase-sync-gateway-doesn%E2%80%99t-see-any-documents-channel-issue