简体   繁体   English

以编程方式断开或连接iPhone呼叫

[英]Disconnect or connect an iPhone call programmatically

I'm working on a personal tweak for iOS. 我正在为iOS进行个人调整。 I want to disconnect/connect a phone call before the phone would show anything. 我想在电话显示任何内容之前断开/连接电话。 I'm hooking into the initWithAlertController: method of class SBUIFullscreenAlertAdapter . 我正在使用类SBUIFullscreenAlertAdapterinitWithAlertController:方法。 Everything is okay when I just show a message that shows the incoming phone number and its name, but when i try to answer the phone call or disconnect it programmatically, it will crash and go to safe mode. 当我只显示一条显示传入电话号码及其名称的消息时,一切正常,但当我尝试接听电话或以编程方式断开连接时,它会崩溃并进入安全模式。

Here is my code: 这是我的代码:

@interface SBUIFullscreenAlertAdapter
- (id)initWithAlertController:(id)arg1;
@end

@interface MPIncomingPhoneCallController
{
    struct __CTCall *_incomingCall;
}
- (id) incomingCallNumber;
- (void)stopRingingOrVibrating;
- (void)answerCall:(struct __CTCall *)arg1;
@end

%hook SBUIFullscreenAlertAdapter
- (id)initWithAlertController:(id)arg1
{
    MPIncomingPhoneCallController *phoneCall = (MPIncomingPhoneCallController*)arg1;
    [phoneCall stopRingingOrVibrating];
    if([phoneCall.incomingCallNumber isEqualToString:@"+98.........."]) {
        [phoneCall answerCall:_incomingCall];
    }
    %orig;
    return self;
}
%end

The error is that it says: "Use of undeclared identifier '_incomingCall'". 错误是它说:“使用未声明的标识符'_incomingCall'”。

How can I solve the problem? 我该如何解决这个问题? Is there a way to use a private instance variable while hooking a method? 有没有办法在挂钩方法时使用私有实例变量? Is there a function which returns a CTCallRef* of the incoming call? 是否有一个函数可以返回来电的CTCallRef* Is there some other way to accomplish this? 有没有其他方法来实现这一目标?

It should be obvious that I'm coding for jailbroken iOS devices, so there is no problem with the use of private frameworks. 很明显,我正在编写越狱的iOS设备,因此使用私有框架没有问题。

There is much better place to do that - MPTelephonyManager -(void)displayAlertForCall:(id)call . 还有更好的地方 - MPTelephonyManager -(void)displayAlertForCall:(id)call This method is located in IncomingCall.servicebundle binary, not in SpringBoard itself. 此方法位于IncomingCall.servicebundle二进制文件中,而不是SpringBoard本身。 This binary is being loaded at runtime into SpringBoard when there is an incoming call. 当有来电时,这个二进制文件在运行时被加载到SpringBoard中。 Before that IncomingCall.servicebundle is not loaded thus you can't hook it's methods. 在没有加载IncomingCall.servicebundle之前,你无法挂钩它的方法。


Hooking IncomingCall.servicebundle 挂钩IncomingCall.servicebundle

In order to hook the method, first, read this How to hook methods of MPIncomingPhoneCallController? 为了挂钩方法,首先,阅读如何挂钩MPIncomingPhoneCallController的方法? SBPluginManager is loading *.servicebundle binaries at runtime. SBPluginManager在运行时加载* .servicebundle二进制文件。 You need to hook it's -(Class)loadPluginBundle:(id)bundle method. 你需要挂钩它-(Class)loadPluginBundle:(id)bundle方法。 It's gonna look something like this: 它看起来像这样:

void displayAlertForCall_hooked(id self, SEL _cmd, id arg1);
void(*displayAlertForCall_orig)(id, SEL, id) = NULL;

%hook SBPluginManager
-(Class)loadPluginBundle:(NSBundle*)bundle
{
    Class ret = %orig;

    if ([[bundle bundleIdentifier] isEqualToString:@"com.apple.mobilephone.incomingcall"] && [bundle isLoaded])
    {
        MSHookMessageEx(objc_getClass("MPTelephonyManager"),
                        @selector(displayAlertForCall:), 
                        (IMP)displayAlertForCall_hooked, 
                        (IMP*)&displayAlertForCall_orig);
    }

    return ret;
}
%end

As you can see, hooking is deferred until IncomingCall.servicebundle is loaded. 如您所见,挂起延迟直到加载IncomingCall.servicebundle I don't know logos/theos that well but I think it can't do that. 我不太了解徽标/ theos,但我认为它不能那样做。 That's why I used CydiaSubstrate (MobileSubstrate) API. 这就是我使用CydiaSubstrate(MobileSubstrate)API的原因。


Hooking MPTelephonyManager 挂钩MPTelephonyManager

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
typedef void* CTCallRef;
void CTCallDisconnect(CTCallRef);
void CTCallAnswer(CTCallRef);    

void displayAlertForCall_hooked(id self, SEL _cmd, id arg1)
{
    CTCallRef call = NULL;
    if (SYSTEM_VERSION_LESS_THAN(@"7.0"))
    {
        //On iOS 6 and below arg1 has CTCallRef type
        call = arg1;
    }
    else
    {
       //On iOS 7 arg1 has TUTelephonyCall* type
       call = [arg1 call];
    }

    NSString *callNumber = (NSString*)CFBridgingRelease(CTCallCopyAddress(NULL, call));
    if ([callNumber isEqualToString:@"+98.........."]) 
    {
        CTCallAnswer(call);
        //CTCallDisconnect(call);
    }

    %orig;
}

For iOS 8.*: 适用于iOS 8. *:

The hooking seems pretty easy with Theos/Logos. 使用Theos / Logos可以很容易地挂钩。

Example Tweak.xm file (you need the TelephonyUtilities private framework headers for 8.1): 示例Tweak.xm文件(您需要8.1的TelephonyUtilities私有框架标头):

#import "TelephonyUtilities/TUTelephonyCall.h"

%hook MPTelephonyManager

-(void)displayAlertForCall:(TUTelephonyCall*)phoneCall { // for iOS 9: displayAlertForCallIfNecessary
    NSLog(@"hooked displayAlertForCall method");
    if ([[NSBundle mainBundle].bundleIdentifier isEqualToString:@"com.apple.springboard"]) { // (don't know if required)
        [phoneCall answer]; // or [phoneCall disconnect];
    }
    %orig;
}

%end


%ctor {
    if ([[NSBundle bundleWithPath:@"/System/Library/SpringBoardPlugins/IncomingCall.servicebundle"] load]) {
        NSLog(@"IncomingCall.servicebundle loaded succesfully!");
    }
    else {
        NSLog(@"IncomingCall.servicebundle did not load succesfully.");
    }
}

Credit to Phillip Tennen ( https://github.com/codyd51/CallConnect ) 感谢Phillip Tennen( https://github.com/codyd51/CallConnect

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM