I used to have deep linking working on Xamarin.iOS with this delegate:
[Register("MyApp.iOS.PushService")]
public class PushService : UAPushNotificationDelegate
{
public override void ReceivedNotificationResponse(UNNotificationResponse notificationResponse, Action completionHandler)
{
try
{
NSString key = new NSString("^d");
if (notificationResponse.Notification.ValueForKey(key) != null)
{
PushClient.HandleNotificationOpened(notificationResponse.Notification.ValueForKey(key).ToString());
}
}
catch (Exception ex)
{
}
completionHandler();
}
}
I was receiving deep link actions to Airship when someone tapped on a push notification... I would pass this into "PushClient" to handle the deep link. (It seemed like Airship used to pass this with field "^d" for some reason, so I just used that and it worked for a long time)
Recently this no longer works, so I'm wondering if this Delegate/Handler is no longer viable? How can I see the whole payload of the push notification now, and/or see the values I tried to pass over from a deep link?
I used to have a .apns file of JSON I'd drag onto an iOS Simulator to mock a deep link push notification but I've lost it. No matter what I put in the .apns file, this delegate function of mine doesn't see any custom keys, either.
Related
I'm looking to implement where a OTP is made a suggestion at the top of the keyboard for an OTP Entry in an IOS app.
The IOS version on the phone is 12.2.
THE ISO SDK Version of my App is 12.1.
Using Visual Studio (Windows) 2017 15.9.13
Now I have done the following......
Created an new control public class OTPEntry : Xamarin.Forms.Entry
Created a renderer for the control and in this I do Control.TextContentType = UITextContentType.OneTimeCode;
I then use this control on a ContentPage with the correct namespace etc.
SO when I am on the form with this control, I send a text to the phone with an OTP. On the phone if I click on the code it offers a "Copy Code" option so it is recognised as an OTP.
However, for the life of me, when I tap in the control, to bring up the keyboard, I do not see the code in the top of the keyboard as expected.
What could I possibly be missing?
It seems the steps to implement this are relatively straightforward but I cannot seem to get it working.
Any ideas, pointers would be very greatly appreciated.
Code below...
CONTROL - IN Xamarin Forms Project
namespace XXXX
{
public class OTPEntry : Xamarin.Forms.Entry
{
public OTPEntry()
{
}
}
}
RENDERER - IN IOS Project
namespace XXXX.YYYY.ZZZZ
{
public class OTPEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.TextContentType = UITextContentType.OneTimeCode;
}
...
...
}
}
}
USAGE - IN CONTENT PAGE IN Xamarin Forms Project
<XXXX:OTPEntry x:Name="txtToken" Keyboard="Numeric" Placeholder="Two Factor Code" HeightRequest="50" WidthRequest="300" TextColor="#2A295B" BackgroundColor="White" Margin="0"/>
Firstly,OneTimeCode is available after iOS 12.0.So I suggest add the following code in CustomRenderer
if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
{
Control.TextContentType = UITextContentType.OneTimeCode;
}
What happens is that when an OTP message receives into the Message Inbox, iOS runs a simple text matching algorithm that determines if that message is a valid OTP message or not and based on that keep a track of it in the memory, then when the user clicks on the OTP AutoFill enabled text field in an app, iOS keyboard popup that OTP as a suggestion in the keyboard. So that your users can fill up the OTP into the app without leaving the app or going back into the Messaging app.
You need to check if the format of OTP is correct .One way to verify whether the text message captcha format is legal is to open [SMS] on the iPhone, click on the message captcha, if from the bottom of the call option copy captcha option, can indicate that it is possible;
And don't forget to open the Autofill Passwords in system setting ->account and password .
So - after verification that the code seemed to be OK and has worked for others I was beginning to think I was going crazy.
I then had a look through the phone settings and discovered "Autofill Passwords" which was turned off.
Once I turned it on, this seems to work as expected.
Experimenting with the Xcode 10 beta, I've created a custom Siri Intent and it's working well. My Intents Extension successfully receives the intents and handles them in turn.
There is no validation of any sort needed on the parameters of the intent, once it is triggered it will request data from the network. I can do this in (void)handle....
I've noticed in my automatically generated Intent class, a list of possible response codes.
typedef NS_ENUM(NSInteger, SMSCheckTeamIntentResponseCode) {
SMSCheckTeamIntentResponseCodeUnspecified = 0,
SMSCheckTeamIntentResponseCodeReady,
SMSCheckTeamIntentResponseCodeContinueInApp,
SMSCheckTeamIntentResponseCodeInProgress,
SMSCheckTeamIntentResponseCodeSuccess,
SMSCheckTeamIntentResponseCodeFailure,
SMSCheckTeamIntentResponseCodeFailureRequiringAppLaunch,
SMSCheckTeamIntentResponseCodeSuccessPlayingNow = 100
}
The failure, success, and success (playing now) responses are defined in my Intents file. The others, such as ready, and in progress, are not, but I'd still like to tell Siri that my extension is "in progress" using the (void)confirm... method.
SMSCheckTeamIntentResponse * const response = [[SMSCheckTeamIntentResponse alloc] initWithCode:SMSCheckTeamIntentResponseCodeInProgress userActivity:nil];
completion(response);
At the moment, when I call this in the confirm method, Siri says something went wrong with my app, and the extension exits.
Does anyone know how to successfully use these response codes?
While working with data sharing between iOS app and Today Extension, I faced the problem that the NSUserDefaultsDidChangeNotification is never sent from either main app or extension when I change UserDefaults. The thing is that I can read and write data to the UserDefaults successfully for the App Group I created. So the data is actually shared by the app and extension. But the notification of the UserDefaults change is never fired (or detected). Can somebody tell me what can be an issue?
The writing of the data in the UserDefaults
NSUserDefaults defaults = new NSUserDefaults("group.com.name1.name2",NSUserDefaultsType.SuiteName);
defaults.SetString("UPDATE " + DateTime.Now.Minute, "data");
defaults.Synchronize();
The notification handler
NSNotificationCenter.DefaultCenter.AddObserver(
NSValueTransformer.UserDefaultsDidChangeNotification, (notification) => {
NSUserDefaults defaults = new NSUserDefaults("group.com.name1.name2",NSUserDefaultsType.SuiteName);
string str = defaults.StringForKey("data");
});
You can use CFNotificationCenter from your container app to post a cross-process notification to your extension app.
Shared Constants:
const string id = "group.sushihangover";
const string key = "LastUpdateTime";
Container app / Setup an observer on your NSUserDefaults object:
var todayWidgetUserDefaults = new NSUserDefaults(id, NSUserDefaultsType.SuiteName);
NSValueTransformer.Notifications.ObserveUserDefaultsDidChange(todayWidgetUserDefaults,(sender, e) =>
{
CFNotificationCenter.Darwin.PostNotification(id, todayWidgetUserDefaults, null, true, true);
});
Today Extension App:
var todayWidgetUserDefaults = new NSUserDefaults(id, NSUserDefaultsType.SuiteName);
void ObserverAction(string notificationId, NSDictionary userInfo)
{
if (notificationId == id)
{
Console.WriteLine(todayWidgetUserDefaults.StringForKey(key));
}
}
var observerToken = CFNotificationCenter.Darwin.AddObserver(id, todayWidgetUserDefaults, ObserverAction, CFNotificationSuspensionBehavior.DeliverImmediately);
Note: App Group entitlements must be setup in both your container app and the Today Extension App.
So, SushiHangover provided perfectly working piece of code.
However, the problem was in the Info.plist file. In order to be able to exchange the notification the Background Mode should be enable for the app with Remote Notification feature. It sounds like a very obvious thing to do, but none of the tutorials for exchanging data between Extension and app with User Defaults that I read mentioned this. Perhaps, it is an obvious thing to do. But I am writing this just in case somebody might have missed this thing too.
I am working with Cordova / PhoneGap plugin PushPlugin and I have it setup pretty well and working, including a test .php and .pem file on my local server using a live device (iPhone 5). IOS 8. There are a couple of issues, with the main one being the call to this function in index.html:
function onNotificationAPN(event) {
console.log(event);
if (event.alert) {
$("#app-status-ul").append('<li>push-notification: ' + event.alert + '</li>');
// showing an alert also requires the org.apache.cordova.dialogs plugin
navigator.notification.alert(event.alert);
}
if (event.sound) {
// playing a sound also requires the org.apache.cordova.media plugin
var snd = new Media(event.sound);
snd.play();
}
if (event.badge) {
pushNotification.setApplicationIconBadgeNumber(successHandler, event.badge);
}
}
The console output for event is:
{"event":"message","payload":{"aps":{"alert":"My first push notification!","sound":"default"}},"foreground":true}
When the App is in the foreground the function onNotificationAPN(event) doesn't fire. "event" appears to be returned in or is converted to JSON format.
The IOS registration line is:
pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});
How can I modify the code to decode the JSON format and display the alert, play sound, set the badge when the application is in the foreground. There must also be some documentation about the formats that the callback can take and the various options. Otherwise, seems to be working.
After a little playing around I guess that the callback "event" is actually already a JSON object:
console.log(e.event);
console.log(e.payload.aps.alert);
console.log(e.payload.aps.sound);
console.log(e.foreground);
prints out message, My first push notification!, default and true in the log.
I don't know if the title say it properly but..
I have a cordova 1.9 app with push notifications using the PushNotification Plugin and UrbanAirship. Everything works fine.
Now I'd like to open a particular page of my app when I lauch/resume my app from a notification.
Is that possible using Javascript ?
I'm totally lost when reading objective-c.
Notifications causes problem to understand JSON structure.
It is not:
if(notifications.length > 0){
But:
if(notifications.notifications.length > 0){
Array is on: notifications.notifications[] structure.
I am not sure how you are trying to load the page but the simplest way would be to call for the pending notifications as it is in javascript and then use window.location.href to load the require page.
I am using this procedure to perform certain task when I have pending notification at application start:
function registerAirship() {
console.log("ready to register for airship");
window.plugins.pushNotification.registerDevice({alert:true, badge:true, sound:true},function(status) {
if (status.deviceToken) {
window.token = status.deviceToken;
if (status) {
registerUAPush(token, "https://go.urbanairship.com/", key, key1, function(){
window.plugins.pushNotification.getPendingNotifications(function(notifications) {
if(notifications.length > 0){
var note = notifications[0];
if(note.applicationLaunchNotification == "1"){
// use the note.aps and redirect to required page
}
}
});
});
} else {
alert("Registration Error: " + status);
}
}
});
}
I was in your position a few days ago. I decided it was easiest to hack objective-c.
So.
1) I found the function that handled my push notification (AppDelegate.m) and called a js function after objective-c had launched execution for handling the notification. After that line, I did this:
[viewController.webView stringByEvaluatingJavaScriptFromString:#"opensometab()"];
2) In the root of my web app application I added this to the pushnotification.js file (you should be able to put it anywhere but I wanted it here).
** My JS function was to activate a tab within the Viewport so yours may be different.
function opensometab(){
var tabPanel = Ext.Viewport.down('tabpanelname');
tabPanel.setActiveItem(3); //index number 3
}