MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init]; if([MFMessageComposeViewController canSendText]) { picker.recipients = [NSArray arrayWithObject:@"1234"]; picker.body = @"Hello"; [picker performSelector:@selector(smsComposeControllerSendStarted:) withObject:[UIButton buttonWithType:UIButtonTypeCustom]]; }
结果没有任何结果.甚至在控制台上都没有失败异常.我都没有在短信应用上看到消息.我发送邮件的人也没有得到它.
可以在这里找到iMars和MFMessageComposeViewController方法的列表.
我写了一个快速代码来验证这些是否是MFMessageComposeViewController中实际存在的项目.
uint varCount = 0; Class cls= [MFMessageComposeViewController class]; Ivar *vars = class_copyIvarList(cls,&varCount); for (uint i = 0; i < varCount; i++) { Ivar var = vars[i]; const char* name = ivar_getName(var); const char* typeEncoding = ivar_getTypeEncoding(var); printf("iVar%i------------> %s\n",i+1,name); } free(vars); Method *imps = class_copyMethodList(cls,&varCount); for (uint i = 0; i < varCount; i++) { SEL sel = method_getName(imps[i]); printf("Method%i------------> %s\n",[(NSStringFromSelector(sel)) UTF8String]); }
它产生以下输出:
iVar1------------> _messageComposeDelegate iVar2------------> _recipients iVar3------------> _body iVar4------------> _subject iVar5------------> _mutableAttachmentURLs iVar6------------> _currentAttachedVideoCount iVar7------------> _currentAttachedAudioCount iVar8------------> _currentAttachedImageCount iVar9------------> _temporaryAttachmentURLs iVar10------------> _attachments Method1------------> disableUserAttachments Method2------------> setCurrentAttachedVideoCount: Method3------------> setCurrentAttachedAudioCount: Method4------------> setCurrentAttachedImageCount: Method5------------> _MIMETypeForURL: Method6------------> _isVideoMIMEType: Method7------------> _isAudioMIMEType: Method8------------> _isImageMIMEType: Method9------------> mutableAttachmentURLs Method10------------> _contentTypeForMIMEType: Method11------------> _updateAttachmentCountForAttachmentURL: Method12------------> _buildAttachmentInfoForAttachmentURL:andAlternameFilename: Method13------------> temporaryAttachmentURLs Method14------------> canAddAttachmentURL: Method15------------> addAttachmentData:withAlternateFilename: Method16------------> _setCanEditRecipients: Method17------------> messageComposeDelegate Method18------------> setMutableAttachmentURLs: Method19------------> currentAttachedVideoCount Method20------------> currentAttachedAudioCount Method21------------> currentAttachedImageCount Method22------------> setTemporaryAttachmentURLs: Method23------------> dealloc Method24------------> viewWillAppear: Method25------------> initWithNibName:bundle: Method26------------> automaticallyForwardAppearanceAndRotationMethodstochildViewControllers Method27------------> setModalPresentationStyle: Method28------------> body Method29------------> setSubject: Method30------------> subject Method31------------> setMessageComposeDelegate: Method32------------> setBody: Method33------------> addAttachmentURL:withAlternateFilename: Method34------------> addAttachmentData:typeIdentifier:filename: Method35------------> attachmentURLs Method36------------> attachments Method37------------> recipients Method38------------> smsComposeControllerCancelled: Method39------------> smsComposeControllerSendStarted: Method40------------> setRecipients:
在我看来,smsComposeControllerSendStarted:方法可能比启动消息发送的实际函数更多的是委托.在上面的方法列表中,没有一个方法签名看起来更接近sendMessage:或类似于实际发送消息的函数.
我的问题是:
1)所有真正的MFMessageComposeViewController都在幕后.或者它是否有一些无法通过运行时函数访问的类集群?
2)如何找出实际的messageSend方法及其实现的类?
任何想法将不胜感激.
谢谢.
解决方法
更新1
在阅读了quellish评论后我发现这个http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/看起来像MFMessageComposeViewController和类似的类为他们的目的启动另一个过程.这些进程是XPC服务,它们实现了应用程序与之通信的特定协议.这些流程使用所有必需的权利进行签名.可能/Applications/MessagesViewService.app/MessagesViewService实际上是发送短信的.这个二进制文件是用com.apple.messages.composeclient签名的,这是为了发送我在ChatKit.framework中找到的this代码所必需的.我认为有一种方法可以手动与该XPC服务进行通信以发送短信,但这将很困难.你不能用类转储和类似的简单工具来搞错,这些工具并没有给你太多的信息.
更新2
我已经成功了解了这一点.我扔掉了所有帮助程序类,所有UI内容都没有真正与XPC服务通信.剩下的就足以显示SMS视图控制器并将一些方法发送到XPC服务而不会有任何障碍.
当我们显示SMS组合UI时,iOS确实会启动/Applications/MessagesViewService.app/MessagesViewService进程.这是XPC服务.您可以尝试在应用程序显示时杀死它 – 您将获得黑屏,这意味着它是正确的.
CKSMSComposeRemoteViewController是显示SMS UI的视图控制器.它是_UIRemoteViewController类的子类.基本上,它管理我们的应用程序与在其他进程中在XPC服务中运行的实际UI之间的连接.这是我如何在我的 – (void)viewDidLoad方法中获取它的实例
_UIAsyncInvocation* cancelationInvocation = [CKSMSComposeRemoveViewController requestViewController:@"CKSMSComposeViewServiceController" fromServiceWithBundleIdentifier:@"com.apple.mobilesms.compose" connectionHandler: ^(CKSMSComposeRemoteViewController* obj,NSError* error){ smsViewController = obj; [smsViewController setDelegate:self]; smsViewControllerProxy = [smsViewController serviceViewControllerProxy]; }];
smsViewController是一个远程视图控制器实例. smsViewControllerProxy是XPCProxy< CKSMSCompose>实现CKSMSComposeViewServiceProtocol协议的实例 – 方法调用将被转发到XPC服务. XPCProxy并没有真正实现这些方法.它实现了forwardInvocation:方法,以便将调用转发到XPC连接.
_UIAsyncInvocation,查看ivar名称cancelationInvocation,用于取消XPC消息.它仅在CKSMSComposeController viewServiceDidTerminateWithError:方法中调用.
[self presentViewController:smsViewController animated:YES completion:NULL];
您可能注意到[smsViewController setDelegate:self].委托必须实现CKSMSComposeRemoteViewControllerDelegate协议或应用程序将崩溃异常(无法识别的选择器).这是我实施的:
-(void)smsComposeControllerAppeared { } -(void)smsComposeControllerCancelled { } -(void)smsComposeControllerDataInserted { }
这足以让你走了.
以下是我们如何向远程视图控制器发送消息:
[smsViewControllerProxy insertTextPart:@"Some text"];
这会将文本插入SMS文本字段并调用smsComposeControllerDataInserted委托方法.
考虑到所有这些,我不再认为我们可以在没有UI的情况下发送短信.实际UI正在另一个进程中运行,我们对它没有任何控制权.我们可以设置一些字段,但就是这样.我希望有一种方法,但事实是,难怪我们做不到.在iOS 6中引入了远程视图来解决这个确切的安全问题 – 在iOS 5上,有一种方法可以在没有用户许可的情况下发送SMS,而一些AppStore应用就是这样做的.所以对Apple赞不绝口.
更新3
我设法在我们与SMS UI交互时转储正在发送的XPC消息.关于日志格式的几句话.第一行 – 拦截消息的地方.它是函数名称或Incoming事件,这意味着它是来自服务的传入消息.连接名称只是XPC连接名称.消息是XPC消息字典内容.消息数据 – 一些XPC消息包含“d” – >“r”键的二进制数据.它是一个序列化的二进制属性列表,无法使用NSPropertyListSerialization反序列化 – 它采用了一些新的格式.相反,你需要使用来自Foundation.framework的NSXPCDecoder – (id)_initWithRootXPCObject:(xpc_object_t).现在转储:
SMS UI正在呈现http://pastebin.com/NVEpujSh
按下“发送”按钮后的SMS UI http://pastebin.com/BYXd2djF
编辑SMS字段时会发送和接收消息,但它们仅对应于UI事件.例如,谁成为第一响应者,那些并不能真正说明SMS UI中发生了什么的东西.