6

In order to support iPhone OS 3.x and 4.0 I programmatically control MFMessageComposeViewController functionality like this (use it only if the OS version is 4.0 or above):

// if iPhone OS version >= 4.0
if (os_version_num >= 4) {
   MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
   if([MFMessageComposeViewController canSendText])
   {
      controller.body = text;
      controller.recipients = [NSArray arrayWithObjects: nil];
      controller.messageComposeDelegate = self;
      [self presentModalViewController:controller animated:YES];
      [controller release];
   }
}

But, when I try to run it on iPhone 3.1.3 device, I immediately get the following error (even before application gets loaded):

dyld: Symbol not found: _OBJC_CLASS_$_MFMessageComposeViewController
  Referenced from: /var/mobile/Applications/7232C474-FAD5-4E28-ABC5-8520F62300B0/TextMe.app/TextMe
  Expected in: /System/Library/Frameworks/MessageUI.framework/MessageUI

Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)

What am I doing wrong?

Darko Hebrang
  • 115
  • 1
  • 8

6 Answers6

17

You need to make sure you're doing a few things:

In your target's build settings:

  • set Base SDK to iPhone Device 4.0
  • set iPhone OS Deployment Target to iPhone OS 3.1.3 (or lower)

In your target's general settings, under Linked Libraries, change the "Type" next to MessageUI.framework to Weak.

Don't import <MessageUI/MFMessageComposeViewController.h> or it will crash on launch in 3.x. Just import <MessageUI/MessageUI.h>

I don't know what os_version_num is, but here's the code I use to test for the availability of MFMessageComposeViewController:

Class smsClass = (NSClassFromString(@"MFMessageComposeViewController"));
if (smsClass != nil && [MFMessageComposeViewController canSendText]) {
   MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
   controller.body = text;
   controller.recipients = [NSArray arrayWithObjects: nil];
   controller.messageComposeDelegate = self;
   [self presentModalViewController:controller animated:YES];
   [controller release];                
}
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
2
Class theClass = NSClassFromString(@"MFMessageComposeViewController");
MFMessageComposeViewController *controller = theClass ? [[theClass alloc] init] : nil;

You can use the type MFMessageComposeViewController as in:

MFMessageComposeViewController *controller;

But you cannot use the global object MFMessageComposeViewController as in:

[MFMessageComposeViewController alloc];

Instead use the class lookup so you are not dependent on the linker:

[NSClassFromString(@"MFMessageComposeViewController") alloc];
drawnonward
  • 53,459
  • 16
  • 107
  • 112
1

In your target parameters, simply set messageUI.framework to type 'weak'

Raphaël Pinto
  • 653
  • 8
  • 20
  • thanks a lot. if you don't do this messageUI.framework to type 'weak' then any above answer will not worked for you. – priyanka Jan 25 '12 at 07:25
0

If you import <MessageUI/MessageUI.h> and set weak reference to MessageUI framework, you can directly call:

   if ([MFMessageComposeViewController canSendText]) {
        controller.body = body;
        controller.recipients = [NSArray arrayWithObjects:number, nil];
        controller.messageComposeDelegate = self;
        [self presentModalViewController:controller animated:YES];
        [controller release]; 
    } else {
        [[UIApplication sharedApplication] openURL: [NSURL URLWithString:[NSString stringWithFormat:@"sms:%@",number]]];
    }

On iOS 3.1.2 you will get nil in the if clause and old method will be launched.

Kacper86
  • 13
  • 4
0

I was having the same problem, and solved it a different way:

On the Left hand-side of your XCode window,

  1. If you scroll down to the Bulls Eye with "Targets" and expand that

  2. Expand your

  3. < control > + < click > on "Link Binary With Libraries"

  4. Choose "Add" --> "Existing Frameworks"

  5. Choose "MessageUI.framework" and click on "Add"

That should add the Message UI to your app, tell me if it works.

Khattab
  • 737
  • 1
  • 10
  • 20
0

What about if you have functions that you only want to include conditionally.

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller   
                 didFinishWithResult:(MessageComposeResult)result {
    [self dismissModalViewControllerAnimated:YES];
}

For example, if the function definition contained MFMessageViewController, how do you make this part conditional (that is, not cause a problem with OS 3.x). Or is it not a problem at all?

DShah
  • 9,768
  • 11
  • 71
  • 127
user648931
  • 503
  • 5
  • 18