OneSignal iOS - Can't prevent webview - ios

I integrated OneSignal to my iOS-App (WKWebview). But its automatically opening another webview window. I just want to load the given URL into my Webview, not another one. Universal Links/Deep Linking is also integrated.
I read that I can give "additional data" to every send notification, but I do not really know how I can catch that inside my AppDelegate (or somewhere else).
I added OneSignal this way:
https://documentation.onesignal.com/docs/ios-sdk-setup

You will want to do this in the AppDelegate.m
The payload will look like this
// (Optional) - Create block that will fire when a notification is tapped on.
id notificationOpenedBlock = ^(OSNotificationOpenedResult *result) {
OSNotificationPayload* payload = result.notification.payload;
NSString* messageTitle = #"OneSignal Example";
NSString* fullMessage = [payload.body copy];
if (payload.additionalData) {
if (payload.additionalData[#"OpenURL"])
redVC.receivedUrl = [NSURL URLWithString:(NSString *)payload.additionalData[#"OpenURL"]];

Related

How to Change UILocalNotification Text after it's shown in notification center?

In one of my app, I want to show the local notification and once it's shown in notification center, I want to updated it's content.
Is it possible in Swift ?
Thanks,
HP.
Not exactly. But you can remove it and add an new one with the new text.
Here's the solution for other visitors:
https://developer.sinnerschrader-mobile.com/ios-how-to-remove-a-notification-programmatically-from-ios-notification-center/582/
Using NSKeyedArchiver, I archived my old local notification to one path and when I wanted to remove it, I deleted it from that location.
It's working fine.
Edited :
1)Cache UILocalNotificaiton using NSKeyedArchiver
NSString *archivePath = [self cachePathWithKey:key];
[NSKeyedArchiver archiveRootObject:notification toFile:archivePath];
2) Show Notification
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
3) Remove Notification Whenever you want to remove it.
NSString *archivePath = [self cachePathWithKey:key];
UILocalNotification *cachedNotification = [self notificationForKey:key];
if (cachedNotification == nil) {
return NO;
}
[[UIApplication sharedApplication] cancelLocalNotification:cachedNotification];
[[NSFileManager defaultManager] removeItemAtPath:archivePath error:nil];
You can use this library also as I've used that one only.
https://github.com/sinnerschrader-mobile/s2m-toolbox-ios
Copy LocalNotificationHelper Folder in your project and User removeNotificationForKey and showNotification methods.
Thanks,
HP.

Facebook iOS SDK 4.1.0 Share Callback

Using the FBSDK mentioned in the title of this question, I present a simple share dialog in a view controller:
// Setup the content for the share
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
content.contentURL = linkUrl;
content.contentDescription = description;
content.contentTitle = title;
content.imageURL = imageUrl;
// Show the share dialog
[FBSDKShareDialog showFromViewController:controller
withContent:content
delegate:someDelegate];
And implement the delegate method...
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results
{
NSLog(#"Sweet, they shared.");
}
So far so good, as long as the user has the Facebook application installed on their device. The issue arises when the user does not have Facebook installed. If this is the case, Safari opens up to a web version of Facebook's login flow (this is fine), but if you then switch back to the original application without logging into Facebook / performing any additional tasks, the completion delegate method shown above is called.
Does anyone have any experience with a workaround for this? It seems like there should be a reliable way for determining whether or not the post did indeed occur.
Note: The above code is pretty pseudo-ish. In the actual implementation I have indeed implemented all of the delegate call backs (didComplete, didCancel, and didFail).
Edit: It turns out, the results dictionary is empty when the completion method is called if the Facebook app is installed on the device. To overcome this, a check needs to be done to see if Facebook is installed first.
Of course after posting I stumbled upon the answer. The results dictionary returned in the didCompleteWithResults method contains a postId key if the share actually occurred. So the logic is as simple as:
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results
{
NSURL *fbURL = [NSURL URLWithString:#"fb://"];
if (![[UIApplication sharedApplication] canOpenURL:fbURL])
if (results[#"postId"]) {
NSLog(#"Sweet, they shared, and Facebook isn't installed.");
} else {
NSLog(#"The post didn't complete, they probably switched back to the app");
}
} else {
NSLog(#"Sweet, they shared, and Facebook is installed.");
}
}
Although this works, it doesn't seem to be a very safe way of going about things (what if Facebook changes the key from "postId" to something else in the future? Unlikely but you get my point).

NSUserActivity handoff not working for custom data

I'm trying to test out the iOS 8.1 handoff feature with NSUserActivity between my iPhone and my iPad. For this, I tried both implementing my own solution, and to use Apple's PhotoHandoff project. However, it's not working.
If I provide a webpageURL, the handover works fine, but when I try to use userData or addUserInfoEntriesFromDictionary nothing works, and I can't for the life of me figure out what the catch is to make the data work.
Sample code:
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:#"com.company.MyTestApp.activity"];
activity.title = #"My Activity";
activity.userInfo = # {};
// activity.webpageURL = [NSURL URLWithString:#"http://google.com"];
self.userActivity = activity;
[self.userActivity becomeCurrent];
[self.userActivity addUserInfoEntriesFromDictionary:# { #"nanananan": #[ #"totoro", #"monsters" ] }];
(I'm also unable to make it work with a Mac app with a corresponding activity type)
I hope you found the solution already, but in case somebody stumbles upon this problem too, here is a solution. (Actually not very different from the previous answer)
Create user activity without userInfo, it will be ignored:
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:#"..."];
activity.title = #"Test activity";
activity.delegate = self;
activity.needsSave = YES;
self.userActivity = activity;
[self.userActivity becomeCurrent];
Implement the delegate to react to needSave events:
- (void)userActivityWillSave:(NSUserActivity *)userActivity {
userActivity.userInfo = #{ #"KEY" : #"VALUE" };
}
When needsSave is set to YES this method will be called and userActivity will be updated.
Hope this helps.
To update the activity object’s userInfo dictionary, you need to configure its delegate and set its needsSave property to YES whenever the userInfo needs updating.
This process is described in the best practices section of the Adopting Handoff guide.
For example, with a simple UITextView, you need to specify the activity type ("com.company.app.edit") identifier in the Info.plist property list file in the NSUserActivityTypes array, then:
- (NSUserActivity *)customUserActivity
{
if (!_customUserActivity) {
_customUserActivity = [[NSUserActivity alloc] initWithActivityType:#"com.company.app.edit"];
_customUserActivity.title = #"Editing in app";
_customUserActivity.delegate = self;
}
return _customUserActivity;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self.customUserActivity becomeCurrent];
}
- (void)textViewDidChange:(UITextView *)textView
{
self.customUserActivity.needsSave = YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
[self.customUserActivity invalidate];
return YES;
}
- (void)userActivityWillSave:(NSUserActivity *)userActivity
{
[userActivity addUserInfoEntriesFromDictionary:#{ #"editText" : self.textView.text }];
}
FWIW, I was having this issue. I was lucky that one of my Activity types worked and the other didn't:
Activity: Walking
(UserInfo x1,y1)
(UserInfo x2,y2)
(UserInfo x3,y3)
Activity: Standing
(UserInfo x4,y4)
Activity: Walking
etc.
I got userInfo if the handoff occured when standing but not walking. I got other properties such as webpageURL in all cases; just userInfo came through null.
The fix for me was to invalidate & recreate the NSUserActivity object every time (e.g. when Walking to x2/y2 from x1/y1), instead of only when Activity type changed (e.g. from walking to standing). This is very much not the way the doc is written, but fixed the issue on iOS 9.
UPDATE: This workaround doesn't work on iOS 8. You need to implement this via the userActivityWillSave delegate, as gregoryM specified. Per Apple's doc:
To update the activity object’s userInfo dictionary efficiently,
configure its delegate and set its needsSave property to YES whenever
the userInfo needs updating. At appropriate times, Handoff invokes the
delegate’s userActivityWillSave: callback, and the delegate can update
the activity state.
This isn't a "best practice", it is required!
[Note: issue occurred on iOS 9 devices running code built on Xcode 6.x. Haven't tested Xcode 7 yet, and issue may not occur on iOS 8.]

message sent to deallocated instance using Pinterest SDK

I'm using the Pinterest iOS SDK to share an item in my iPad app. The following snippet of code will always crash with a message sent to deallocated instance on the line with the comment:
NSString *clientId = [NSMutableString stringWithString:#"1431665"];
NSLog(#"clientId: %#", clientId);
Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
NSLog(#"gone: %#", clientId); // <- CRASH!
I'm using NSMutableString stringWithString to simulate the conditions in my app. I don't actually use that line in my code.
Even if don't output the clientId on the last line, the app crashes when leaving the block. I assume it's because ARC is trying to release the reference which has already been deallocated.
It seems like the Pinterest SDK must be doing something wonky and trashing the string I'm passing in. Is there some way I can get around this while they fix their code?
EDIT 1
Simplified the test case.
EDIT 2
It looks like the Pinterest SDK is consuming the clientId argument. Based on the clang ARC documentation, the way to indicate this to clang is to indicate this with __attribute((ns_consumed)).
New question: Is it possible to indicate this to ARC without modifying the signature of the method to add the attribute?
EDIT 3
So this works, but it's ugly as sin? Is there another way?
NSString *clientId = [NSMutableString stringWithString:#"1431665"];
[clientId performSelector:NSSelectorFromString(#"retain")]; // <- UGLY!
NSLog(#"clientId: %#", clientId);
Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
NSLog(#"gone: %#", clientId);
What I did was make a static variable that represented the Pinterest class:
//I put this outside my #implementation code at the top of my m file
static Pinterest *_pinterest = nil;
// instantiating
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_pinterest = [[Pinterest alloc] initWithClientId:clientId];
});
I think that Pinterest assumed that everyone would use their class as a static singleton because that's probably what they do internally. To be fair, I don't foresee using multiple client ID's with a single app in most cases. I agree, though, this is a stupefying oversight on their part. They didn't even document this behavior, what were they thinking?!
My current workaround, which seems to be the least hacky of the ideas so far is this wrapper class that doesn't use ARC:
+ (void) createPinWithClientId:(NSString *)clientId
imageURL:(NSURL *)imageURL
sourceURL:(NSURL *)sourceURL
description:(NSString *)descriptionText {
Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
[pinterest createPinWithImageURL:imageURL
sourceURL:sourceURL
description:descriptionText];
}
The key is to disable ARC for the class, which keeps the runtime from deallocating the clientId.

iCloud - renaming open documents on another device sometimes fails

The issue: I'm working on an iCloud document on device A, e.g. iPod Touch. Then I change the name of the document on device B, e.g. my Mac (via the Finder). The change goes up to the cloud and after a pause device A gets to hear about it.
And then:
some of the time all is just fine - I pick up the change of name via a changed fileURL property and can update my interface accordingly - the document continues to behave just as it should
some of the time, the document's fileURL is returned as something such as: file://localhost/var/mobile/Library/Mobile%20Documents/.ubd/peer-43A0AEB6-84CE-283E-CA39-FCC4EF3BC8F8-v23/ftr/purg-012fdcfbe3b3bbce6e603fdfd2f000b2cb28649e95 Not surprisingly this file won't save.
Can anyone explain what is going on and how to work around it?
Background
The name change is picked up fine by by NSMetadataQuery. So, for e.g., I can rename documents that are not open and all my iCloud functionality works fine. The issue only seems to occur with open documents.
Other iCloud features are working fine, e.g. I can change content on one device, e.g. my Mac, and detect and then update my interface on another device, e.g. my iPod Touch, that has the relevant iCloud document open.
I first spotted this when I added an override for presentedItemDidMoveToURL: to my UIDocument subclass. The override reliably picks up name changes made in the cloud, e.g. renaming the document on another device. Then sometimes newURL is the final expected URL for the renamed document, i.e. something sensible from which I can extract the new name use `lastPathComponent', update my interface etc. On other occasions newURL is a document in some other directory with a last path component beginning 'purg-', e.g. purg-012fdcfbe3b3bbce6e603fdfd2f000b2cb28649e95.
- (void) presentedItemDidMoveToURL:(NSURL *) newURL;
{
[super presentedItemDidMoveToURL: newURL];
if ([(id)[self delegate] respondsToSelector:#selector(documentNameChanged:)])
{
[[self delegate] documentNameChanged: self];
}
}
The presentedItemDidMoveToURL: method does not seem to be the root cause of the problem. For example, if I don't override that method at all, but periodically check in the viewController that is looking after the open document, then sometimes after a rename fileURL will return the new name and sometimes it will return `purg-.....'. So the issue appears to be to do with how renaming is handled.
Update
As al_lea pointed out, the issue here was related to accommodatePresentedItemDeletionWithCompletionHandler:. Expanding on al_lea's answer, I added the code below to my UIDocument subclass. This fixed the issue.
- (void) accommodatePresentedItemDeletionWithCompletionHandler: (void (^) (NSError *errorOrNil)) completionHandler
{
PresentedDocument* presentedDocument = [self retain];
[presentedDocument closeWithCompletionHandler: ^(BOOL success) {
NSError* error = nil;
if (!success)
{
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
#"Could not close document that is being deleted on another device",
NSLocalizedDescriptionKey, nil];
error = [NSError errorWithDomain: #"some_suitable_domain"
code: 101
userInfo: userInfo];
}
completionHandler(error); // run the passed in completion handler (required)
dispatch_async(dispatch_get_main_queue(), ^
{
[[NSNotificationCenter defaultCenter] postNotificationName: NOTIFY_presentedDocumentDeletedOnAnotherDevice
object: presentedDocument
userInfo: nil];
[presentedDocument tidyUpAfterDelete]; // app specific tidy up
[presentedDocument release];
});
}];
}
With this code in place, there are no spurious and confusing presentedItemDidMoveToURL: calls made and, in addition, the relevant object can listen for notifications of deletions on other devices.
This type of URL appears when a UIDocument is opened on local and get deleted from a remote device:
file://localhost/var/mobile/Library/Mobile%20Documents/.ubd/peer-43A0AEB6-84CE-283E-CA39-FCC4EF3BC8F8-v23/ftr/purg-
You need to close the document first before it get deleted - detect this in NSFilePresenter's accommodatePresentedItemDeletionWithCompletionHandler:

Resources