以编程方式断开或接通iPhone电话



我正在为iOS做一个个人调整。我想在电话显示任何东西之前断开电话。我连接到类SBUIFullscreenAlertAdapterinitWithAlertController:方法。当我只是显示一条显示传入电话号码及其名称的消息时,一切都很好,但是当我试图接听电话或以编程方式断开电话时,它会崩溃并进入安全模式。

下面是我的代码:
@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

错误是它说:"使用未声明的标识符'_incomingCall'"。

我该如何解决这个问题?是否有一种方法来使用一个私有实例变量,而挂钩的方法?是否有一个函数返回传入呼叫的CTCallRef* ?有没有其他方法可以做到这一点?

很明显,我是在为越狱的iOS设备编码,所以使用私有框架是没有问题的。

有更好的地方做到这一点- MPTelephonyManager -(void)displayAlertForCall:(id)call。该方法位于IncomingCall.servicebundle二进制文件中,而不是在SpringBoard本身中。当有传入呼叫时,这个二进制文件将在运行时加载到SpringBoard中。在此之前,IncomingCall.servicebundle没有加载,因此你不能挂钩它的方法。


连接IncomingCall.servicebundle

为了钩子方法,首先,阅读这个如何钩子MPIncomingPhoneCallController的方法?SBPluginManager正在加载*。运行时的Servicebundle二进制文件。你需要钩住它的-(Class)loadPluginBundle:(id)bundle方法。它看起来像这样:

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

可以看到,钩子被延迟到IncomingCall.servicebundle被加载。我不太了解logos/theos,但我认为它做不到这一点。这就是为什么我使用CydiaSubstrate (MobileSubstrate) API。


连接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;
}

iOS 8。*:

对于Theos/Logos来说,钩子似乎很容易。

调整示例。xm文件(对于8.1,您需要telephonyuutilities私有框架头文件):

#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.");
    }
}

来源:Phillip Tennen (https://github.com/codyd51/CallConnect)

最新更新