How to exit from Map App in IOS 6 i.e. return control back to app requesting directions? - ios6-maps

I am using MKMapItem to launch Map app from within my app after the user taps 'Directions' button. The Map app comes up fine showing directions from current location to a address. But how do I go back to my app, If I no longer want to see Directions? Below is my code attached to IBAction.
Code:
- (IBAction)pressDirectionsButton:(id)sender {
Class mapItemClass = [MKMapItem class];
if (mapItemClass && [mapItemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)])
{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
NSString *addressString = [NSString stringWithFormat:#"%#,%#,%#,%#,%#",
self.currentlySelectedTemple.houseNumber,
self.currentlySelectedTemple.street,
self.currentlySelectedTemple.city,
self.currentlySelectedTemple.state,
self.currentlySelectedTemple.country];
[geocoder geocodeAddressString:addressString completionHandler:^(NSArray *placemarks, NSError *error) {
//Convert CLPlacemark to an MKPlacemark
CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc]
initWithCoordinate:geocodedPlacemark.location.coordinate addressDictionary:geocodedPlacemark.addressDictionary];
//Create a map item for geocoded address to pass to Maps app
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:geocodedPlacemark.name];
//Set Directions mode to Driving
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
//Get the "Current User Locations" MKMapItem
MKMapItem *currentLocationMapItem = [MKMapItem mapItemForCurrentLocation];
//Pass the current location and destination map items to Maps app
[MKMapItem openMapsWithItems:#[currentLocationMapItem, mapItem] launchOptions:launchOptions];
}];
}
}

There is no way to go back to your app (programatically), as you are no longer in your app, but in the Maps app. After executing openMapsWithItems:launchOptions:, your App Delegate's applicationdDidEnterBackground: method is called.
Currently there is no way to use Mapkit to embed a map with directions within your app.

Related

Save bitmap to gallery and access it through local notification

In an app, I am taking a screenshot of the content of a page, and I want to save it in the Gallery, create a local notification with the image in it, and when the user taps on it, it open the image from the Gallery.
As of now, I am able to take the snapshot and save it using this :
var path = MediaStore.Images.Media.InsertImage(context.ContentResolver, bitmap, "TestImage.png", "Snapshot taken");
I have a few problems with this approach, I can see the image in the Pictures folders from the Gallery, but the name is not the one I specified in this case "TestImage.png". Also, the path returned from this call has the URI scheme "content://...".
After that, I create the local notification with NotificationCompat.Builder with the embedded image, it works well. But when I try to add the PendingIntent to it to open the image I have an issue with the path returned from InsertImage call. The path returned is :
content://media/external/images/media/1292
I tried this :
var path = FileProvider.GetUriForFile(CrossCurrentActivity.Current.AppContext, "com.myapp.fileprovider", new File(path));
but it doesn't work, I get an exception :
Java.Lang.IllegalArgumentException: Failed to find configured root that contains /content:/media/external/images/media/1292
I also tried this :
global::Android.Net.Uri.FromFile(new File(path)), "image/*")
but I receive another exception :
Android.OS.FileUriExposedException: file:///content%3A/media/external/images/media/1292 exposed beyond app through Intent.getData()
This is the code I use to create the notification:
NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();
picStyle.BigPicture(bitmap);
picStyle.SetSummaryText("The snapshot has been saved to your library");
const int pendingIntentId = 0;
PendingIntent pendingIntent =
PendingIntent.GetActivity(CrossCurrentActivity.Current.Activity, pendingIntentId,
new Intent().SetAction(Intent.ActionView)
.SetDataAndType(global::Android.Net.Uri.FromFile(new File(path)), "image/*"), PendingIntentFlags.OneShot);
NotificationCompat.Builder builder = new NotificationCompat.Builder(CrossCurrentActivity.Current.AppContext, "UniqueID")
.SetContentIntent(pendingIntent)
.SetContentTitle("Security center")
.SetContentText("The snapshot has been saved to your library")
.SetSmallIcon(Resource.Drawable.ic_notification);
builder.SetStyle(picStyle);
Notification notification = builder.Build();
NotificationManager notificationManager =
CrossCurrentActivity.Current.Activity.GetSystemService(Context.NotificationService) as NotificationManager;
const int notificationId = 0;
notificationManager.Notify(notificationId, notification);
Do you guys have any idea on how I could save the image with the right name in the Public Gallery folder then access it in the PendingIntent for the local notification ?
Thank you all !
Okay so after a few hours of trial and error, I found out the issue, when parsing the path returned from the MediaStore.Images.Media.InsertImage, I had to use global::Android.Net.Uri.Parse() and not Uri.FromFile(), the latter is only if your path has the URI scheme "file://". By doing that I was able to make the ContentIntent work on the local notification. Only problem now is the name of the file that's not respected.

Copying plist to App Group Container - iOS 8

I am adding an App Group to my app for sharing a single plist between the app and the watch. I used to copy a plist from the bundle to Documents for when the app first started up. But with the watch I am now trying to convert it to save to the container but it always seems to be empty. The targets have app group enabled, and I am using the right name in my code. What could be going wrong?
Old Way
// COPY PLIST TO DOCUMENTS
NSFileManager *fileManger=[NSFileManager defaultManager];
NSError *error;
NSArray *pathsArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *doumentDirectoryPath=[pathsArray objectAtIndex:0];
NSString *destinationPath= [doumentDirectoryPath stringByAppendingPathComponent:#"badger.com.vacations.plist"];
NSLog(#"plist path %#",destinationPath);
if (![fileManger fileExistsAtPath:destinationPath]){
NSString *sourcePath=[[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:#"badger.com.vacations.plist"];
[fileManger copyItemAtPath:sourcePath toPath:destinationPath error:&error];
}
New way - not working
// COPY PLIST TO CONTAINER
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.xxxxx.xxx.container"];
containerURL = [containerURL URLByAppendingPathComponent:#"name.com.data.plist"];
NSString *destinationPath= containerURL.path;
NSLog(#"destinationPath %#", containerURL);
NSString *sourcePath=[[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:#"name.com.data.plist"];
[fileManger copyItemAtPath:sourcePath toPath:containerURL.path error:&error];
You can´t share a plist as a file (or I simply don´t know about this feature), instead you just generate a new NSUserDefaults instance, which is shareable between targets.
Have a look here:
https://devforums.apple.com/message/977151#977151
or the Apple documentation
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
In the Apple Member Center, under 'Identifiers > App Groups' register a new App Group (e.g. group.de.myApp.sharedGroup)
In the Apple Member Center, under 'Identifiers > App IDs' refresh your App Ids for the targets that need sharing to use the App Groups feature
Regenerate all needed Provisioning Profiles and get them into Xcode
Back to Xcode: Under 'Capabilities' in each of your targets that need to share data, set 'App Groups' to on and add the previously registered App group.
Talk to the shareable NSUserDefaults container like this:
Store stuff:
NSUserDefaults *groupDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.de.myApp.sharedGroup"];
[groupDefaults setInteger:1337 forKey:#"testEntry"];
[groupDefaults synchronize];
Read stuff:
NSUserDefaults *groupDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.de.myApp.sharedGroup"];
NSInteger testEntry = [groupDefaults integerForKey:#"testEntry"];
NSLog(#"testEntry: %ld", (long)testEntry);

ios - SWRevealViewController segue to last view in navigation controller when receive push notification

I'm using SWRevealViewController 2.3.0 in my project. My storyboard is designed as below:
http://i.stack.imgur.com/txv0G.png
When the app is not running (completely terminated) and a push notification comes, how to get the Detail view controller showed up with a Back button to go back Main view controller? Some notification values should have passed to the Detail view.
Thanks for any help.
What i am doing in this type of case is
you can check if launchOptions is not nil didFinishLaunchingWithOptions as
if (launchOptions)
{
NSDictionary *dic = [launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"];
[[NSUserDefaults standardUserDefaults] setObject:[dic objectForKey:#"aps"] forKey:#"PushNotification"];
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"PushNotification"];
}
and save in user Defaults as i did.
Now simply When you are in mainViewController you can check it as
NSDictionary *notification = [[NSUserDefaults standardUserDefaults] objectForKey:#"PushNotification"];
if (notification)
{
// check the dictionary "Push Notification" Key Values that you are receiving to go in `DetailViewController`
// Now go to `DetailViewContoller` having your details from `PushNotification`by `performSegueWithIdentifier`
[self performSegueWithIdentifier:#"DetailViewController" sender:self];
// make this value nil for normal use
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"PushNotification"];
}
if you don't make this userDefaults value nil here, you can use it in DetailViewController too, but don't forget to make nil after use.
Using this way your BACK button should show in DetailViewController

ios8 customizing interactive push notifications

I'm trying to find an updated doc that includes any info / code samples on the new interactive push notifications. The guide I found on Local & Remote Push Notifications still shows the payload size is 256 bytes. My understanding is that in ios8 that limit has been raised to 2k.
I'm also trying to find documentation on how to add custom buttons to make my notifciations interactive. I don't see very much in the push notification programming guide.
How do I setup a category to add custom buttons with colors? Any documentation on this would be useful.
You can create interactive notifications by defining the action buttons in iOS8.
Create UIMutableUserNotificationAction buttons.
Then Create UIMutableUserNotificationCategory and group above actions into category.
Add all categories into set.
Create UIUserNotificationSettings with this category set.
Register notifications with this settings
Add category field in push payload and send notification
Please find below the sample code:
- (void) registerRemoteNotificationWithActions{
//1. Create action buttons..:)
UIMutableUserNotificationAction *shareAction = [[UIMutableUserNotificationAction alloc] init];
shareAction.identifier = #"SHARE_IDENTIFIER";
shareAction.title = #"Share";
shareAction.activationMode = UIUserNotificationActivationModeForeground;
shareAction.destructive = NO;
shareAction.authenticationRequired = YES;
//2. Then create the category to group actions.:)
UIMutableUserNotificationCategory *shareCategory = [[UIMutableUserNotificationCategory alloc] init];
shareCategory.identifier = #"SHARE_CATEGORY";
[shareCategory setActions:#[shareAction] forContext:UIUserNotificationActionContextDefault];
[shareCategory setActions:#[shareAction] forContext:UIUserNotificationActionContextMinimal];
//3. Then add categories into one set..:)
NSSet *categories = [NSSet setWithObjects:shareCategory, nil];
//4. Finally register remote notification with this action categories..:)
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
}
Sample payload format :
{
"aps": {
"badge": 1,
"alert": "Hello world!",
“category”: “SHARE_CATEGORY”
}
}
And handle the actions using the following method :
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
if ([identifier isEqualToString:#"SHARE_IDENTIFIER"] ){
}
}
You can check this link for more info.
This is a tutorial I found in youtube for custom action push notification. It is done in swift.
https://www.youtube.com/watch?v=Yh3lLpV1k_Y

Is there a way to access ALAssets information outside of resultBlock?

Okay so I have my ImagePicker all setup and the ALAssetLibrary setup to get the Picture and Title (if it exists for existing pictures or generic text for a new picture) but now I'm trying to figure out if there's a way I can access this information outside of the block call from the assetForURL method. So here's my code just so I can show what's happening (this is in the viewDidLoad method of a screen that is displayed after a picture selection is made)
__block NSString *documentName;
__block UIImage *docImage;
NSURL *resourceURL = [imageInfo objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *asset)
{
ALAssetRepresentation *imageRep = [asset defaultRepresentation];
//Get Image
CGImageRef iref = [imageRep fullResolutionImage];
//If image is null then it's a new picture from Camera
if (iref == NULL) {
docImage = [imageInfo objectForKey:UIImagePickerControllerOriginalImage];
documentName = #"New Picture";
}
else {
docImage = [UIImage imageWithCGImage:iref];
documentName = [imageRep filename];
}
};
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary *imageAsset = [[ALAssetsLibrary alloc] init];
[imageAsset assetForURL:resourceURL resultBlock:resultblock failureBlock:nil];
Now I want to be able to use the two variables (documentName and docImage) elsewhere in this ViewController (for example if someone wants to change the name of the document before they save it I want to be able to revert back to the default name) but I can't seem to figure out what I need to do so these variables can be used later. Don't know if this makes much sense or not, so if I need to clarify anything else let me know.
Okay so I figured out that the problem wasn't with the code but with my logic on how I was using it. I was trying to do this on the Modal View that was presented after an image was selected instead of just doing this in the ImagePicker screen and then calling the Modal window inside of the result block code.

Resources