- 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中发生了什么的东西.