开发一个发送短信的应用程序






4.97/5 (50投票s)
能够通过互联网连接从iPhone发送短信,这有多么棒?
背景
在我的文章 "如何从桌面应用程序发送短信" 中,我提到了 CardBoardFish,这是一个简单易用的API,用于在全球范围内发送短信。
SendSMS 应用
该应用非常基础和简单。它只有一个屏幕,看起来像这样
基本上,您输入发件人的姓名或号码(可以是任何内容),收件人的国家代码和电话号码以及一条消息,然后按“发送”。
然后发送消息,并弹出一个确认号。
该应用最重要的构建块是 Send
例程(在 ViewController.m 中)
- (void) send {
@autoreleasepool {
NSString *url = [NSString stringWithFormat:
@"http://sms1.cardboardfish.com:9001/HTTPSMS?S=H&UN=%@&P=%@&DA=%@%@&SA=%@&M=%@&DC=4",
@"<PLACE YOUR USER NAME HERE>", @"<PLACE YOUR PASSWORD HERE", txtCountryCode.text,
txtDestinationNo.text, txtName.text,[self stringToHex:txtMessage.text]];
url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url %@", url);
NSError* connError = 0;
NSURLResponse* response;
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20];
NSData* data = [ NSURLConnection sendSynchronousRequest:
request returningResponse:&response error:&connError ];
NSString* resp = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"response: %@", resp);
与设备的通讯录交互
为了方便地从您的 iPhone 中选择现有联系人,使用了 openContacts
例程,该例程使用了一个名为 ABPeoplePickerNavigationController 的类,根据 Apple 的说法,它“实现了一个视图控制器,该控制器管理一组视图,允许用户从通讯录中选择一个联系人或其联系人信息项之一”。
- (IBAction)openContacts:(id)sender {
ABPeoplePickerNavigationController *picker =
[[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
NSArray *displayedItems = [NSArray arrayWithObjects:
[NSNumber numberWithInt:kABPersonPhoneProperty],
[NSNumber numberWithInt:kABPersonEmailProperty],
[NSNumber numberWithInt:kABPersonBirthdayProperty], nil];
picker.displayedProperties = displayedItems;
[self presentModalViewController:picker animated:YES];
[picker release];
}
从通讯录中选择一个条目后,我们会对其执行一些基本的清理操作,例如删除前导零和空格、破折号和括号。因此,数字“(04) 888-3333
”变为“48883333
”,这是 SDK 所需的格式。
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)
peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
property);
if (ABMultiValueGetCount(phoneNumbers) > 0) {
phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, identifier);
} else {
phone = @"[None]";
}
phone = [phone stringByReplacingOccurrencesOfString:@"(" withString:@""];
phone = [phone stringByReplacingOccurrencesOfString:@")" withString:@""];
phone = [phone stringByReplacingOccurrencesOfString:@"-" withString:@""];
phone = [phone stringByReplacingOccurrencesOfString:@" " withString:@""];
if ([[phone substringWithRange:NSMakeRange(0, 1)] isEqual:@"0"] ) {
phone = [phone substringFromIndex:1];
}
txtDestinationNo.text = phone;
[self dismissModalViewControllerAnimated:YES];
return NO;
}
国家标志
我添加的一个不错的部分是国家列表以及每个国家的国旗。虽然不是真的必要……我使用了 226 个名为每个国旗的国家代码的 .PNG 图像,所以 49.png 包含德国国旗,依此类推...
然后 CountryCodesViewController.m 源文件看起来像这样
#import "CountryCodesViewController.h"
@interface CountryCodesViewController ()
@end
@implementation CountryCodesViewController
@synthesize mainViewController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"Flags"];
countryCodes = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:sourcePath error:NULL];
[countryCodes retain];
}
- (void)viewDidUnload
{
[tblCountryCodes release];
tblCountryCodes = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[tblCountryCodes release];
[super dealloc];
}
#pragma mark UITableView methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [countryCodes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
NSString *strFlagName = [countryCodes objectAtIndex:indexPath.row];
cell.textLabel.text = [strFlagName substringToIndex:[strFlagName length] - 4];
cell.imageView.image =
[UIImage imageNamed:[NSString stringWithFormat:@"Flags/%@",strFlagName]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *strFlagName = [countryCodes objectAtIndex:indexPath.row];
[mainViewController selectCountryCode:
[strFlagName substringToIndex:[strFlagName length] - 4]];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)okPressed:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
@end
错误处理
当发生错误时,会出现一个错误代码,指示错误的性质。HTTPSMS SDK 文档解释了每个错误号。
可能出现几种导致传输失败的情况。
第一个是连接错误。如果 iPhone 未连接到互联网,则可能发生此类错误。在这种情况下,我们希望提醒用户,并将短信放入队列中,以便在 iPhone 连接到互联网时发送。我们还希望,如果设备离线期间编写了几条短信,它们都将被放入队列中,并在可能的情况下进行传输。
此示例不执行任何逻辑错误检查(例如验证电话号码、国家代码等的格式),并且无论如何,只有在将消息发送到 Web 服务后,才可能会出现其他错误代码。
if ( connError ) {
NSLog(@"%@",[connError description]);
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
[message setValue:txtCountryCode.text forKey:@"countryCode"];
[message setValue:txtDestinationNo.text forKey:@"destinationNo"];
[message setValue:txtName.text forKey:@"name"];
[message setValue:txtMessage.text forKey:@"message"];
[self performSelectorOnMainThread:@selector(addToQueue:)
withObject:message waitUntilDone:NO];
[message release];
UIAlertView* alert = [[UIAlertView alloc] init];
alert.title = @"Send SMS";
alert.message = @"Can't access Internet.
The message will be queued to be sent later";
[alert addButtonWithTitle:@"Ok"];
[alert show];
[alert release];
} else {
UIAlertView* alert = [[UIAlertView alloc] init];
alert.title = @"Send SMS";
alert.message = resp;
[alert addButtonWithTitle:@"Ok"];
[alert show];
[alert release];
if ([resp rangeOfString:@"OK"].location != NSNotFound) {
[self performSelectorOnMainThread:@selector(sendComplete)
withObject:nil waitUntilDone:YES];
}
}
[resp release];
}
loadingView.hidden = YES;
}
延伸阅读
关注点
如果您需要有关 iOS 开发的帮助,请阅读这篇 文章。
Michael Haephrati , CodeProject MVP 2013
历史
- 2013年2月16日:初始版本