For an app to launch Safari with some URL, the code must call the openURL
method of UIApplication
.
You can block such calls by subclassing UIApplication
and overriding both the old and new openURL
methods (the iOS 10+ and pre iOS 10 versions). Your implementation of these overridden methods can simply do nothing if your app has no need to open any URLs or your can check the URL and only allow URLs you know your app should be making.
The trick is to install your custom UIApplication
class.
In Objective-C you need to update main.m by passing in your custom class to the third parameter to the call to UIApplicationMain
. By default this parameter will be nil
.
Updated main.m:
#import <UIKit/UIKit.h>
#import "MyApplication.h"
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv,
NSStringFromClass([MyApplication class]),
NSStringFromClass([AppDelegate class]));
}
}
Custom UIApplication
:
#import "MyApplication.h"
@implementation MyApplication
- (void)openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options completionHandler:(void (^)(BOOL))completion {
// optionally allow some URLs as needed
NSLog(@"block %@", url);
if (completion) {
completion(YES);
}
}
- (BOOL)openURL:(NSURL *)url {
// optionally allow some URLs as needed
NSLog(@"block %@", url);
return YES;
}
@end
In Swift you need to remove the use of @UIApplicationMain
in AppDelegate.swift, add main.swift, and add a call to UIApplicationMain
to that file.
Here is an example custom UIApplication
:
import UIKit
class MyApplication: UIApplication {
override func open(_ url: URL, options: [String : Any] = [:], completionHandler completion: ((Bool) -> Void)? = nil) {
// optionally allow some URLs as needed
print("block \(url)")
completion?(true)
}
override func openURL(_ url: URL) -> Bool {
// optionally allow some URLs as needed
print("block \(url)")
return true
}
}
Here is an example main.swift (courtesy of https://stackoverflow.com/a/24021180/1226963):
import Foundation
import UIKit
UIApplicationMain(
CommandLine.argc,
UnsafeMutableRawPointer(CommandLine.unsafeArgv)
.bindMemory(
to: UnsafeMutablePointer<Int8>.self,
capacity: Int(CommandLine.argc)),
NSStringFromClass(MyApplication.self),
NSStringFromClass(AppDelegate.self)
)