I am building an app that takes advantage of 4.0 features like in-app messaging but I also want my app to work on all 3.x versions. How do I check if the device can use MFMessageComposeViewController?
Apple advises to use the NSClassFromString function to determine if the class is available. Don't forgot to weak link against the message framework as mentioned before.
Example from the MessageComposer sample:
-(IBAction)showSMSPicker:(id)sender {
// The MFMessageComposeViewController class is only available in iPhone OS 4.0 or later.
// So, we must verify the existence of the above class and log an error message for devices
// running earlier versions of the iPhone OS. Set feedbackMsg if device doesn't support
// MFMessageComposeViewController API.
Class messageClass = (NSClassFromString(#"MFMessageComposeViewController"));
if (messageClass != nil) {
// Check whether the current device is configured for sending SMS messages
if ([messageClass canSendText]) {
[self displaySMSComposerSheet];
}
else {
feedbackMsg.hidden = NO;
feedbackMsg.text = #"Device not configured to send SMS.";
}
}
else {
feedbackMsg.hidden = NO;
feedbackMsg.text = #"Device not configured to send SMS.";
}
}
Link: MessageComposer sample
Update: The sample code I posted checks for the availability of the SMS composer, checking for the mail composer is similar.
Try this:
#import <MessageUI/MessageUI.h>
#include <dlfcn.h>
if ( dlsym(RTLD_DEFAULT, "MFMailComposeErrorDomain") != NULL ) {
// MFMessageComposeViewController framework is available
} else {
// do alternative for no MFMessageComposeViewController
}
Don't forget to weak link the MFMessageUI framework.
You could check the device's current operating system using the UIDevice class.
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html
The systemName and systemVersion properties may be what you're looking for. You'll also need to weak link the framework!
Related
I am developing an app which has call and message functionality , i want to check if sim card is installed or not coz i am facing problem with messaging as it gives alerts for " Message Sent Successful"
Please help me out.
There might be different ways but one way is by using MFMessageComposeViewController class to see if you can send the text message. If you can then sim is available otherwise not.
if ([MFMessageComposeViewController canSendText]) {
NSLog(#"SIM Available");
} else {
NSLog(#"no SIM card installed");
}
In cases you have iMessage available then this might return you true, you could also check if you can make a call, you might want to use CTTelephonyNetworkInfo for that purpose.
You can also check using like this.... First read this doc
http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html#//apple_ref/doc/uid/TP40009596-CH1-SW1
NSString *_code = [[[CTCarrier alloc] init] mobileCountryCode];
The value for this property is nil if any of the following apply:
The device is in Airplane mode.
There is no SIM card in the device.
The device is outside of cellular service range.
First you have to be sure that device is iPhone (not iPod or iPad) then check if device can make call or not, just like this............
if([[UIDevice currentDevice].model isEqualToString:#"iPhone"])
{
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"tel:123456"]])
{
NSLog(#"Device can make call or send message");
}
else
{
NSLog(#"Device can not make call or send message");
}
}
else
{
NSLog(#"Device can not make call or send message");
}
Hope it will help you........
After looking around I could not get a straight answer to the following case: can I link to a book in the iBook store from my iphone app without integrating the in-app purchases API?
As far as I know, iBooks does charge you for placing the book, so my logic says that it should be possible since otherwise you would be charged twice.
Many thanks.
If your app is targeting iOS 6.0 you can use the new SKStoreProductViewController to allow users to purchase iTunes, App Store, and iBooks content directly from your app without having to leave it.
Here is how to present it from a UIViewController. You must add the StoreKit.framework to your application.
ViewController.h
#import <StoreKit/StoreKit.h>
#interface UIViewController : UIViewController <SKStoreProductViewControllerDelegate>
#end
ViewController.m
-(void)showProductPageForProductID:(NSInteger)productID {
SKStoreProductViewController *sv = [[SKStoreProductViewController alloc] init];
sv.delegate = self;
NSDictionary *product = #{ SKStoreProductParameterITunesItemIdentifier: #(productID)};
[sv loadProductWithParameters:product completionBlock:^(BOOL result, NSError *error) {
if(result)
[self presentModalViewController:sv animated:YES];
else {
//product not found, handle appropriately
}
}];
}
-(void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
[viewController dismissModalViewControllerAnimated:YES];
}
If your targeting devices below iOS 6.0 you can just use this:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://itunes.apple.com/us/book/the-casual-vacancy/id518781282?mt=11"]];
Just replace that URL string with your link, and it will leave your app and enter the iBooks app displaying that product.
If you want to target both iOS 6.0 and lower, you can just check if they have the new SKStoreProductViewController by using the following conditional
if([SKStoreProductViewController class]) {
//show the SKStoreProductViewController
}
else {
//use UIApplication's openURL:
}
In order to get the Apple product ID for a product, you can just check the URL to the product for example:
http://itunes.apple.com/us/book/the-casual-vacancy/id518781282?mt=11
The product ID is 518781282. It comes after the id portion in the URL. Don't include the ? or anything after it.
I am fairly new to iOS Development and I've always wondered if a user running my application on iOS 4 were to try and run this code:
//POST TWEET//
- (void)showTweetSheet
{
TWTweetComposeViewController *tweetSheet =
[[TWTweetComposeViewController alloc] init];
tweetSheet.completionHandler = ^(TWTweetComposeViewControllerResult result) {
switch(result) {
case TWTweetComposeViewControllerResultCancelled:
break;
case TWTweetComposeViewControllerResultDone:
break;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:^{
NSLog(#"Tweet Sheet has been dismissed.");
}];
});
};
[tweetSheet setInitialText:#"Check out this cool picture I found on #Pickr_"];
// Add an URL to the Tweet. You can add multiple URLs.
if (![tweetSheet addURL:[NSURL URLWithString:ImageHost]]){
NSLog(#"Unable to add the URL!");
}
[self presentViewController:tweetSheet animated:YES completion:^{
NSLog(#"Tweet sheet has been presented.");
}];
}
What would happen? Would the application just terminate with an error or will the code just not run? And how do I properly implement features that are OS specific? Would I just use something like this:
NSString *DeviceVersion = [[UIDevice currentDevice] systemVersion];
int DeviceVersionInt = [DeviceVersion intValue];
if (DeviceVersionInt > 5)
{
//do something.
}
else
{
//don't do a thing.
}
It will crash on iOS 4 if you write iOS5 features without checking if they are available or not. Try to implement Twitter like this
Class twClass = NSClassFromString(#"TWTweetComposeViewController");
if (!twClass) // Framework not available, older iOS
{
//use iOS4 SDK to implement Twitter framework
}
else {
//use Apple provided default Twitter framework
}
Make sure you have added Twitter Framework with weak link.
Id imagine that it would work the same as with any other api. If you link against a function which is not in a previous version, the program will crash on an attempt to call the function. Therefore, version switches are used, as you demonstrated, to avoid crashes.
The app would crash. If you want to implement features based on iOS, you can use a variety of methods. See this question.
I need to write a background application in iOS which listens to incoming phone calls on the iPhone.
Is it possible? Can anyone suggest some good pointers ?
Thankyou
This would be very much against Apple's privacy policy and there's no chance an app like this would be approved.
There are call recording apps that sneak around this restriction, though, but they use third party services and no actual built-in iPhone API's.
You can do it in applicationWillEnterForeground using CTCallCenter's CTCallState properties. Don't forget to import the CoreTelephony framework. Here's an example:
#import <CoreTelephony/CTCall.h>
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[callCenter setCallEventHandler:^(CTCall *call) {
if ([[call callState] isEqual:CTCallStateIncoming] || [[call callState] isEqual:CTCallStateDialing]) {
if ([viewController isPlaying])
{
NSLog(#"Call was started.");
}
} else if ([[call callState] isEqual:CTCallStateDisconnected]) {
if (callWasStarted)
{
NSLog(#"Call was ended.");
}
}
}];
}
I'm running up against problems trying to incorporate some iOS5-specific libraries into an app targeted at both iOS5 and iOS4.3. I've gone through the following steps:
weakly-linked the Twitter framework by setting it as optional in 'Link Binary with Libraries"
added it as a framework for the iOS5.0 SDK in Other Linker Flags with `-framework Twitter.framework'
conditionally linked the framework in the class header:
#if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
#import <Twitter/Twitter.h>
#import <Accounts/Accounts.h>
#endif
then in the method itself, I'm then checking whether the user's set up for Twitter:
if ([TWTweetComposeViewController class]) {
self.canTweet = [TWTweetComposeViewController canSendTweet];
}
This works beautifully on both the 5.0 and 4.3 simulators. However, I've got problems getting it to run on, or archive for, actual devices.
When I've got either a 3GS running 5.0, or a 4 running 5.0 attached, both show up twice in the Scheme dropdown. Selecting the top one, and attempting build or run the project fails with an Use of unidentified identifier 'TWTweetComposeViewController' error.
Using the second device entry, the build fails with a ld: framework not found Twitter.framework error.
I'm sure there's something I'm missing here, but I'm stumped. Can anyone advise?
If you are using a week linking then you have to check first availability of API using
NSClassFromString, respondsToSelector, instancesRespondToSelector etc.
So, change your if condition. First try to get your class object using above specified runtime function.
here is a link explaining in detail how to do such.
link
The code for presenting twitter controller
Before this you have to add the frameworks as optional and make the import in h file if iOS is min iOS 5
Class TWTweetComposeViewControllerClass = NSClassFromString(#"TWTweetComposeViewController");
if (TWTweetComposeViewControllerClass != nil) {
if([TWTweetComposeViewControllerClass respondsToSelector:#selector(canSendTweet)]) {
UIViewController *twitterViewController = [[TWTweetComposeViewControllerClass alloc] init];
[twitterViewController performSelector:#selector(setInitialText:)
withObject:NSLocalizedString(#"TwitterMessage", #"")];
[twitterViewController performSelector:#selector(addURL:)
withObject:url];
[twitterViewController performSelector:#selector(addImage:)
withObject:[UIImage imageNamed:#"yourImage.png"]];
[self.navigationController presentModalViewController:twitterViewController animated:YES];
[twitterViewController release];
}
}
Further digging into the error thrown back by the compiler suggested that it was ignoring the weak link flag. Although I've no idea how or why, it was fixed by a reinstallation of XCode.
if you link to 4.2 or later and deploy to 3.1 or later, you can use the new weak linking features to make this check simple.
you have to add Twitter frameworks as optional and then
Class TWTweetComposeViewControllerClass = NSClassFromString(#"TWTweetComposeViewController");
if (TWTweetComposeViewControllerClass != nil)
{
if([TWTweetComposeViewControllerClass respondsToSelector:#selector(canSendTweet)])
{
UIViewController *twitterViewController = [[TWTweetComposeViewControllerClass alloc] init];
[twitterViewController performSelector:#selector(setInitialText:)
withObject:NSLocalizedString(#"TwitterMessage", #"")];
[twitterViewController performSelector:#selector(addURL:)
withObject:url];
[twitterViewController performSelector:#selector(addImage:)
withObject:[UIImage imageNamed:#"yourImage.png"]];
[self.navigationController presentModalViewController:twitterViewController animated:YES];
[twitterViewController release];
}
}