现在的位置: 首页 > 综合 > 正文

iOS调用外部程序和系统程序

2014年09月05日 ⁄ 综合 ⁄ 共 3811字 ⁄ 字号 评论关闭

首先贴一个链接,本文主要参考了该博客,结合自己的理解写了小Demo并说一说个人的理解:IOS-应用之间调用

每个iOS开发者都知道在iOS系统中各个程序是高度相互独立的Sandbox机制,所以程序之间交流数据甚至程序A调用程序B这种事似乎是有点遥远的事,但是苹果官方也提供了方法让我们去实现。

就个人理解来看,原理非常简单,就是通过App A的AppA-info.plist文件为本程序建立一个对外接口,然后App B通过该接口调用App A。例如Safari浏览器的接口就是http,如果要在程序App中打开Safari浏览器,只要在App中用代码打开URL:http://www.csdn.net(为csdn卖个广告)就可以了,其中http指定我们要打开的是Safari(该浏览器的对外程序接口),后面的www.csdn.net就是我们通过Safari浏览器对应的一个子功能的接口。

系统程序的接口见Apple URL Scheme Reference


好了,原理说完了,下面说说利用该功能实现的一个简单的Demo:

先看看故事板,只有一个视图控制器:



头文件的代码如下:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

- (IBAction)openSafari:(id)sender;

- (IBAction)openHelloApp:(id)sender;

@property (weak, nonatomic) IBOutlet UITextField *phoneNumber_textField;
- (IBAction)phone:(id)sender;

@property (weak, nonatomic) IBOutlet UITextField *message_textField;
- (IBAction)sendMessage:(id)sender;

@end

实现代码如下:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    UITapGestureRecognizer *tapInView = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];
    [self.view addGestureRecognizer:tapInView];
}

- (void)hideKeyboard:(id)sender {
    [self.phoneNumber_textField resignFirstResponder];
    [self.message_textField resignFirstResponder];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)openSafari:(id)sender {
    NSURL *safariURL = [NSURL URLWithString:@"http://www.csdn.net"];
    [[UIApplication sharedApplication] openURL:safariURL];
}

- (IBAction)openHelloApp:(id)sender {
    NSURL *url = [NSURL URLWithString:@"hello://subhello"];
    [[UIApplication sharedApplication] openURL:url];
}

- (IBAction)phone:(id)sender {
    self.phoneNumber_textField.keyboardType = UIKeyboardTypePhonePad;
    
    NSString *phoneNumber = nil;
    if (self.phoneNumber_textField.text && ![self.phoneNumber_textField.text isEqualToString:@""]) {
        phoneNumber = self.phoneNumber_textField.text;
    }
    
    NSString *urlString = [NSString stringWithFormat:@"tel://%@", phoneNumber];
    NSURL *phoneURL = [NSURL URLWithString:urlString];
    [[UIApplication sharedApplication] openURL:phoneURL];
}

- (IBAction)sendMessage:(id)sender {
    self.message_textField.keyboardType = UIKeyboardTypePhonePad;
    
    NSString *phoneNumber = nil;
    if (self.message_textField.text && ![self.message_textField.text isEqualToString:@""]) {
        phoneNumber = self.message_textField.text;
    }
    
    NSString *urlString = [NSString stringWithFormat:@"sms://%@", phoneNumber];
    NSURL *messageURL = [NSURL URLWithString:urlString];
    [[UIApplication sharedApplication] openURL:messageURL];
}

@end

Run(注意真机调试,否则无法使用拨号和短信功能):

首先是程序界面:


点击打开Safari按钮,程序将打开Safari浏览器并转到CSDN主页:


再点击打开HelloApp,程序将打开另一个接口名为Hello的程序(关于自定义程序的对外接口将在下面补充),该程序的ViewController的背景颜色为绿色:


接着在拨号按钮上面的输入框中输入联系人的电话号码,然后点击拨号按钮:


然后就弹出通话状态了(很牛叉,这样我们就可以自己做一个拨号器了):

还有一个发短信,功能差不多,先输入联系人号码,然后点击发信息按钮:


接着弹出发送信息的界面:



的确,这种直接调用系统或自己写的程序的方式功能是非常强大的,而且实现也非常简单,只需要简单的设定程序的接口URL和用UIApplication调用就可以了。


还有一个问题,怎么自定义我们自己程序的对外接口呢?答案是修改程序的-Info.plist文件:



参考博文中根据官方文档这样给出CFBundleURLTypes的定义:

表1-6  CFBundleURLTypes属性的键和值

CFBundleURLName

这是个字符串,表示URL类型的抽象名。为了确保其唯一性,建议您使用反向DNS风格的标识,比如com.acme.myscheme

这里提供的URL类型名是一个指向本地化字符串的键,该字符串位于本地化语言包子目录中的InfoPlist.strings文件中。本地化字符串是人类可识别的URL类型名称,用相应的语言来表示。

CFBundleURLSchemes

这是个URL模式的数组,表示归属于这个URL类型的URL。每个模式都是一个字符串。属于指定URL类型的URL都带有它们的模式组件

其中URL Schemes指定程序的对外接口,URL identifier指定子功能接口。例如Safari对外的主要接口是http,子接口例如www.csdn.net,调用方法就是http://www.csdn.net,即[URL Scheme]://[URL identifier](某些系统的App是不需要//的,但是有//没有问题),通过这种唯一的URL标识我们可以指定打开外部程序后想要获取的服务。

后面还有程序被外部程序打开后的处理方法:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    NSLog(@"%@", url.scheme);
    return YES;
}

当外部程序调用本程序时是否要处理的方法。

如果下列方法

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation

已经被实现,那么handleOpenURL方法不会被执行(被后者覆盖)。

如果返回NO将不会执行delegate的will/didFinishLauchingWithOptions方法,但程序依然被打开。


好吧,对于这部分内容还有很多方面我只是一知半解的,只是大概知道了怎么用而已。

详情请参考我开头给出的链接。

Demo已经上传,有兴趣的可以下载来看看。

抱歉!评论已关闭.