how to check if Mapkit is available or not? - iphone

I am building an application that is using Mapkit. I know that this is only available in IOS6.
So I should check if this is available or not. I am using the following code.
if(NSClassFromString(#"MKMapKit")) {
// MKMapKit is available in this OS
CLLocationCoordinate2D coords =
CLLocationCoordinate2DMake(51.097185,5.621653);
NSDictionary *address = #{
(NSString *)kABPersonAddressStreetKey: #"Weg naar oqdffds 59",
(NSString *)kABPersonAddressCityKey: #"Msfsf",
(NSString *)kABPersonAddressStateKey: #"Limbusqfqsdf",
(NSString *)kABPersonAddressZIPKey: #"3670",
(NSString *)kABPersonAddressCountryCodeKey: #"BE",
(NSString *)kABPersonPhoneMainLabel:#"04741234567"
};
MKPlacemark *place = [[MKPlacemark alloc]
initWithCoordinate:coords addressDictionary:address];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:place];
mapItem.phoneNumber = #"0141343252";
//current location
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
}else {
NSLog(#"tot hier");
// MKMapKit is not available in this OS
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
}
But for some reason or another it always use the google method.
Can anybody help!

As already mentioned, MapKit has been available well before iOS 6.
What you want to check for is MKMapItem (not "MKMapKit").
However, as the documentation for MKMapItem explains (with a code example):
To determine whether a class is available at runtime in a given iOS
release, you typically check whether that class is nil. Unfortunately,
this test is not cleanly accurate for MKMapItem. Although this class
was publicly available starting with iOS 6.0, it was in development
prior to that. Although the class exists in earlier releases, you
should not attempt to use it in those releases.
To determine at runtime whether you can use map items in your
application, test whether the class and the
openMapsWithItems:launchOptions: class method exist. That method was
not added to the class until iOS 6.0. The code might look like the
following:
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass
respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
// Use class
}
So this check:
if(NSClassFromString(#"MKMapKit")) {
should be:
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
or:
Class itemClass = NSClassFromString(#"MKMapItem");
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {

MkMapKit is available in ios 4.3, too, probably in 3.x, too!
What is new, is (like in all Releases), some new methods of MkMapKit:
You should better check for that specific method you need
(geocoding ?=
Look into the headers of MkMapKit you are importing (if i remeber correctly: MkMapKit.h), there are Macros defining the availability
of a specifc method, depending on the ios version.

Related

How to draw routes on maps in ios 6?

I want to show maps & draw routes on maps. My application supports for ios 4 plus. So how should i use maps to work on ios 6 as well as before. Also i want to know sholud i use custom mapview in my app to display maps & routes or should i use
[[UIApplication sharedApplication] openURL:]
I have never user MapKits. So please provide if any tutorial. Also let me know if there are any rd party libraries that can be used.
If you don't want an in-app map. Use the following:
NSString *destinationAddress = #"Amsterdam";
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count] > 0) {
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithPlacemark:[placemarks objectAtIndex:0]];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placeMark];
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
} else {
//error nothing found
}
}];
return;
} else {
NSString *sourceAddress = [LocalizedCurrentLocation currentLocationStringForCurrentLanguage];
NSString *urlToOpen = [NSString stringWithFormat:#"http://maps.google.com/maps?saddr=%#&daddr=%#",
[sourceAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[destinationAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlToOpen]];
}
This opens the map application and checks if it is ios5 or ios6.
For ios5 I use the LocalizedCurrentLocation from this post http://www.martip.net/blog/localized-current-location-string-for-iphone-apps
For ios6 I use the CLGeocoder to get the placemark and then open the map with it and the current location.
Remember to add CoreLocation.framework and MapKit.framework
I think this'll help you:
http://developer.decarta.com/Apis/IOS/Tutorial/Lesson6
http://developer.decarta.com/Apis/IOS/Tutorial/Lesson6Example
Or this?
http://spitzkoff.com/craig/?p=136
Maybe this is fun to do if you want data in your map:
http://www.raywenderlich.com/21365/introduction-to-mapkit-in-ios-6-tutorial
Or some basic information about Mapkit
http://www.techotopia.com/index.php/Working_with_Maps_on_the_iPhone_with_MapKit_and_the_MKMapView_Class

Do I need to release an MKMapItem or placemark objects?

Of the tutorials I've found online (e.g. http://bit.ly/SIXlI5) and the Apple documentation, none make mention of releasing MKMapItem or the placemarks. Do they need to be released, and if not, why not? Does the Maps app take care of all that?
NSDictionary *address = #{
(NSString *)kABPersonAddressStreetKey: _address.text,
(NSString *)kABPersonAddressCityKey: _city.text,
(NSString *)kABPersonAddressStateKey: _state.text,
(NSString *)kABPersonAddressZIPKey: _zip.text
};
MKPlacemark *place = [[MKPlacemark alloc]
initWithCoordinate:_coords
addressDictionary:address];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:place];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving
};
[mapItem openInMapsWithLaunchOptions:options];
If you're not using ARC, and you alloc an object, you are responsible for releasing it. That's all there is to it.
In this case, when you call openInMaps..., the map item info is encoded in a URL that's sent to the Maps app. But you dont need to worry about that.
You can expect that unless it's called out in headers or documentation, an instance method will do its work synchronously and not release the receiver.

MapKit in iOS 6 - How to Find Places Nearby...?

Using MapKit in iOS 6, how am I'm supposed to get nearby locations without having their specific coordinates? I'm also unsure if it's still possible...err...allowed...to use Google Maps API to accomplish this goal, as this is the only way I can think of to do this. I know everything is still in beta, but I've still found no information anywhere about this topic, on forums, in Apple's new MapKit Documentation, anywhere. All I want to do is perform a search for locations (let's say, parks, for example) within 'x' miles of the user's location.
It seems that since Apple has developed their own Maps application, they should have a way to accomplish this using MapKit or Core Location...right?
Try with this code. This may help to you.
URLManager *urlmanager = [[URLManager alloc] init];
urlmanager.delegate = self;
urlmanager.responseType = JSON_TYPE;
urlmanager.commandName = #"Search";
NSString *locationString = [NSString stringWithFormat:#"%f,%f",latitude,longitude];
//Location where you want to search
NSString *key = #"AIzaSyCNRpero6aM451X0IfgFHAd-Y3eJUssqoa8`enter code here`0E";
//This is the secret key which you will get from the Google API Console when you register your app.
NSString *radiuos = #"15000";
//This is the area within which you want to search
NSString *keyword = #"Hotel";//Search keyword you want to search
NSMutableDictionary *arguments = [[NSMutableDictionary alloc] init]; // zero argument
[arguments setValue:key forKey:#"key"];
[arguments setValue:locationString forKey:#"location"];
[arguments setValue:radiuos forKey:#"radius"];
[arguments setValue:#"true" forKey:#"sensor"];
[arguments setValue:keyword forKey:#"keyword"];
NSLog(#"Arguments are %#",arguments);
[urlmanager urlCallGetMethod:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json"] withParameters:arguments];

Is it possible to get information about all apps installed on iPhone?

Is it possible to get the information (app icon, app name, app location) about all apps that have been installed on iPhone/iPod?
there is a way to check if an application is installed or not, however, it does violate the Sandbox rules and Apple *may reject your app for using this. But it has been done before by other Apps that are available in the App Store, so feel free to try it
Sometimes you may want to check if a specific app is installed on the device, in case you use custom URL schemes that require some other app to be installed (you could just gray out/disable some buttons then). Unfortunately, Apple apparently does not have any function that checks this for you, so I whipped one up. It does not enumerate every single app, instead it uses the MobileInstallation cache which is always up-to-date with SpringBoard and holds the Info dictionaries of all apps installed. Although you're not "supposed" to access the cache, it's readable by App Store apps. Here is my code which at least works perfectly fine with the Simulator 2.2.1:
Code:
// Declaration
BOOL APCheckIfAppInstalled(NSString *bundleIdentifier); // Bundle identifier (eg. com.apple.mobilesafari) used to track apps
// Implementation
BOOL APCheckIfAppInstalled(NSString *bundleIdentifier)
{
static NSString *const cacheFileName = #"com.apple.mobile.installation.plist";
NSString *relativeCachePath = [[#"Library" stringByAppendingPathComponent: #"Caches"] stringByAppendingPathComponent: cacheFileName];
NSDictionary *cacheDict = nil;
NSString *path = nil;
// Loop through all possible paths the cache could be in
for (short i = 0; 1; i++)
{
switch (i) {
case 0: // Jailbroken apps will find the cache here; their home directory is /var/mobile
path = [NSHomeDirectory() stringByAppendingPathComponent: relativeCachePath];
break;
case 1: // App Store apps and Simulator will find the cache here; home (/var/mobile/) is 2 directories above sandbox folder
path = [[NSHomeDirectory() stringByAppendingPathComponent: #"../.."] stringByAppendingPathComponent: relativeCachePath];
break;
case 2: // If the app is anywhere else, default to hardcoded /var/mobile/
path = [#"/var/mobile" stringByAppendingPathComponent: relativeCachePath];
break;
default: // Cache not found (loop not broken)
return NO;
break; }
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir) // Ensure that file exists
cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
if (cacheDict) // If cache is loaded, then break the loop. If the loop is not "broken," it will return NO later (default: case)
break;
}
NSDictionary *system = [cacheDict objectForKey: #"System"]; // First check all system (jailbroken) apps
if ([system objectForKey: bundleIdentifier]) return YES;
NSDictionary *user = [cacheDict objectForKey: #"User"]; // Then all the user (App Store /var/mobile/Applications) apps
if ([user objectForKey: bundleIdentifier]) return YES;
// If nothing returned YES already, we'll return NO now
return NO;
}
Here is an example of this, assuming that your app is named "yourselfmadeapp" and is an app in the app store.
Code:
NSArray *bundles2Check = [NSArray arrayWithObjects: #"com.apple.mobilesafari", #"com.yourcompany.yourselfmadeapp", #"com.blahblah.nonexistent", nil];
for (NSString *identifier in bundles2Check)
if (APCheckIfAppInstalled(identifier))
NSLog(#"App installed: %#", identifier);
else
NSLog(#"App not installed: %#", identifier);
Log Output:
Code:
2009-01-30 12:19:20.250
SomeApp[266:20b] App installed:
com.apple.mobilesafari 2009-01-30
12:19:20.254 SomeApp[266:20b] App
installed:
com.yourcompany.yourselfmadeapp
2009-01-30 12:19:20.260
SomeApp[266:20b] App not installed:
com.blahblah.nonexistent
Try this out before using it, I think Apple changed where the MobileInstallation.plist is located and if you do change it, try it out on an actual device not the simulator. Good Luck!
http://www.iphonedevsdk.com/forum/iphone-sdk-development/37103-finding-out-what-apps-installed.html
PK
Sure you can do this when the device is Jailbroken, so that you can reach out of the sandBox.
You can get the information you want by analyzing Info.plist in every .app which is located at every path "/var/mobile/Applications/", such as "/var/mobile/Applications//*.app/Info.plist"
Here is my code.
- (void)scan
{
NSString *pathOfApplications = #"/var/mobile/Applications";
NSLog(#"scan begin");
// all applications
NSArray *arrayOfApplications = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathOfApplications error:nil];
for (NSString *applicationDir in arrayOfApplications) {
// path of an application
NSString *pathOfApplication = [pathOfApplications stringByAppendingPathComponent:applicationDir];
NSArray *arrayOfSubApplication = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathOfApplication error:nil];
// seek for *.app
for (NSString *applicationSubDir in arrayOfSubApplication) {
if ([applicationSubDir hasSuffix:#".app"]) {// *.app
NSString *path = [pathOfApplication stringByAppendingPathComponent:applicationSubDir];
path = [path stringByAppendingPathComponent:#"Info.plist"];
// so you get the Info.plist in the dict
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
// code to analyzing the dict.
}
}
}
NSLog(#"scan end");
}
Here is sample content of an Info.plist. So, get values for any key you care about.
{
BuildMachineOSBuild = 11G63;
CFBundleDevelopmentRegion = "zh_CN";
CFBundleDisplayName = "\U4e50\U89c6\U5f71\U89c6HD";
CFBundleExecutable = LetvIpadClient;
CFBundleIconFile = "icon.png";
CFBundleIconFiles = (
"icon.png",
"icon#2x.png"
);
CFBundleIdentifier = "com.letv.ipad.hdclient";
CFBundleInfoDictionaryVersion = "6.0";
CFBundleName = LetvIpadClient;
CFBundlePackageType = APPL;
CFBundleResourceSpecification = "ResourceRules.plist";
CFBundleShortVersionString = "3.1";
CFBundleSignature = "????";
CFBundleSupportedPlatforms = (
iPhoneOS
);
CFBundleURLTypes = (
{
CFBundleURLName = "m.letv.com";
CFBundleURLSchemes = (
letvIPad
);
}
);
CFBundleVersion = "3.1";
DTCompiler = "com.apple.compilers.llvmgcc42";
DTPlatformBuild = 10A403;
DTPlatformName = iphoneos;
DTPlatformVersion = "6.0";
DTSDKBuild = 10A403;
DTSDKName = "iphoneos6.0";
DTXcode = 0450;
DTXcodeBuild = 4G182;
LSRequiresIPhoneOS = 0;
MinimumOSVersion = "4.3";
UIDeviceFamily = (
2
);
"UILaunchImageFile~ipad" = (
"Default.png",
"Default#2x.png"
);
UIPrerenderedIcon = 1;
UIStatusBarHidden = 1;
UISupportedInterfaceOrientations = (
UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight
);
"UISupportedInterfaceOrientations~ipad" = (
UIInterfaceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeLeft
);
}
Another way to get installed applications in iPhone is just call:
NSString *rootAppPath = #"/Applications";
NSArray *listApp = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:rootAppPath error:nil];
You can access then in each application to read their dictionary Info.plist to know more about these applications.
UPDATE: Obviously, this method does not work anymore (for iOS8) cause our application does not have permission to view the content of /Applications
try this, it will work even with non-jailbroken devices
#include <objc/runtime.h>
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSLog(#"apps: %#", [workspace performSelector:selectorALL]);

iphone gps cllocation and making variables globally accessible

I'm pretty new to iPhone development and have been trying to work out how to include GPS information into an app I'm working on.
I've gone through the HelloThere tutorial, which is a great start
http://www.mobileorchard.com/hello-there-a-corelocation-tutorial/
And had no problems getting this to run on my iPhone. I then took the example and have since been trying to incorporate the GPS info into a much larger and more complicated app. The larger application has an existing function which will send a post request to the server, and I'd like to simply provide the location data, specifically the coordinate.latitude and coordinate.longitude to this function, if possible without altering it.
This is pretty trivial in the other languages I've worked with but it's turned out to be quite challenging in objective C.
Basically, as per the tutorial I have gotten to the point where I'm logging the location info,
//GPS stuff
- (void)locationUpdate:(CLLocation *)location {
//locationLabel.text = [location description];
locationString = [location description];
locationLabel.text = locationString;
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
}
but I can't figure out how I can then make the locLat and locLong variables available to other parts of the application. Pretty lame but I'm still a bit lost with objective C.
There are many ways to do this. The quick and dirty way (and some will frown upon it) is to just declare those as globals in this file and use extern to access them from other files.
Better is to make those #properties of the class, and provide a getter so you can access those from another class or part of the app. That does assume that this class will be available for other classes to access later on.
You also can use delegate to get information. And...
Thinking a bit more, I would probably store data like this someplace else, and will use this routine to update the value in that location (by using a setter of that class), so this method here would just get the location and then store it elsewhere.
You might want to read Scott Knaster's book on Objective C and Mac development for a primer on Obj C.
Here's how I recommend doing it:
Store lat/long in a dictionary and fire them off as strings bundled in a notification. Setup an observer in the application delegate and have the callback function store the lat/long in class properties of the application delegate and/or store them in the application defaults.
In your class where you acquire the coordinates:
- (void)locationUpdate:(CLLocation *)location {
NSString *locationString, *locLat, *locLong;
locationString = [location description];
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
NSDictionary *locationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:locationString, #"description",
locLat, #"latitude", locLong, #"longitude", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateSearchLocation"
object:self userInfo:locationDictionary];
}
In your application delegate class:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Listen for search coordinates broadcast
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(setCoordinates:)
name:#"updateSearchLocation" object:nil];
}
- (void)setCoordinates:(id)sender {
self.latitude = [[sender userInfo] objectForKey:#"latitude"];
self.longitude = [[sender userInfo] objectForKey:#"longitude"];
NSLog(#"location = %#", [[sender userInfo] objectForKey:#"description"]);
}
Dont forget to setup the class properties in the application delegate header file as NSString. You can then access the coordinates by calling directly from the application delegate:
YourAppDelegateClassName *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"lat = %#, long = %#", appDelegate.latitude, appDelegate.longitude);
Or you can access them anywhere from the user defaults:
[[NSUserDefaults standardUserDefaults] objectForKey:#"latitude"];
[[NSUserDefaults standardUserDefaults] objectForKey:#"longitude"];
I hope that helps.