Fix first launch and package hook as a signed framework
This commit is contained in:
1 parent
c1d0293404
commit
97a4fad71f
6 files changed
+147
-20
No files matched your search
+67
-10
@@ -36,6 +36,7 @@ static NSString *WBLocalized(NSString *key)
|
||||
@"scanning_containers_short": @"Scanning system containers…", @"ls_found": @"LaunchServices database located",
|
||||
@"init_failed": @"Initialization Failed", @"ok": @"OK",
|
||||
@"no_group": @"No usable App Group; worse_query cannot run",
|
||||
@"no_group_hint": @"Re-sign with a certificate and provisioning profile that include an App Group entitlement.",
|
||||
@"no_ls": @"LaunchServices database not found",
|
||||
@"no_containers": @"The LaunchServices database returned no containers",
|
||||
},
|
||||
@@ -47,6 +48,7 @@ static NSString *WBLocalized(NSString *key)
|
||||
@"scanning_containers_short": @"正在扫描系统容器…", @"ls_found": @"已定位 LaunchServices 数据库",
|
||||
@"init_failed": @"初始化失败", @"ok": @"好",
|
||||
@"no_group": @"未找到可用的 App Group,无法执行 worse_query",
|
||||
@"no_group_hint": @"请使用包含 App Group 权限的证书和描述文件重新签名。",
|
||||
@"no_ls": @"未找到 LaunchServices 数据库",
|
||||
@"no_containers": @"LaunchServices 数据库没有返回容器列表",
|
||||
},
|
||||
@@ -780,9 +782,17 @@ static void (*gOrigLoad)(id, SEL);
|
||||
static NSString *(*gOrigFileSizeString)(id, SEL);
|
||||
static void WBStartPreparation(void);
|
||||
static BOOL (*gOrigDidFinishLaunching)(id, SEL, UIApplication *, NSDictionary *);
|
||||
static CFAbsoluteTime gLaunchStarted;
|
||||
|
||||
static BOOL WBHookDidFinishLaunching(id self, SEL _cmd, UIApplication *application, NSDictionary *launchOptions)
|
||||
{
|
||||
gLaunchStarted = CFAbsoluteTimeGetCurrent();
|
||||
// The original app shows a one-time "Message From Developer" alert that
|
||||
// competes with the launch progress sheet and makes the first run look
|
||||
// blank. The hook has its own launch status UI, so skip it.
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
[defaults setBool:YES forKey:@"FirstLaunch"];
|
||||
[defaults synchronize];
|
||||
BOOL result = gOrigDidFinishLaunching ? gOrigDidFinishLaunching(self, _cmd, application, launchOptions) : YES;
|
||||
WBStartPreparation();
|
||||
return result;
|
||||
@@ -790,13 +800,29 @@ static BOOL WBHookDidFinishLaunching(id self, SEL _cmd, UIApplication *applicati
|
||||
|
||||
static __weak id gAppsTableViewController;
|
||||
static WBProgressViewController *gProgressController;
|
||||
static dispatch_semaphore_t gReadySemaphore;
|
||||
static NSCondition *gReadyCondition;
|
||||
static BOOL gPrepared;
|
||||
static BOOL gPreparing;
|
||||
static BOOL gWaitingForRoot;
|
||||
static BOOL gReloadScheduled;
|
||||
|
||||
static BOOL WBWaitForRegistry(void)
|
||||
{
|
||||
if (WBRegistry.shared.ready) return YES;
|
||||
if (!gReadyCondition) return NO;
|
||||
[gReadyCondition lock];
|
||||
NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:120];
|
||||
while (!WBRegistry.shared.ready && !gPrepared && deadline.timeIntervalSinceNow > 0) {
|
||||
[gReadyCondition waitUntilDate:deadline];
|
||||
}
|
||||
BOOL ready = WBRegistry.shared.ready;
|
||||
[gReadyCondition unlock];
|
||||
return ready;
|
||||
}
|
||||
|
||||
static NSArray *WBHookAllInstalled(id self, SEL _cmd)
|
||||
{
|
||||
if (!WBRegistry.shared.ready) WBWaitForRegistry();
|
||||
NSArray *proxies = WBRegistry.shared.proxies;
|
||||
if (WBRegistry.shared.ready && proxies.count) return proxies;
|
||||
return gOrigAllInstalled ? gOrigAllInstalled(self, _cmd) : @[];
|
||||
@@ -804,6 +830,7 @@ static NSArray *WBHookAllInstalled(id self, SEL _cmd)
|
||||
|
||||
static NSArray *WBHookAllApplications(id self, SEL _cmd)
|
||||
{
|
||||
if (!WBRegistry.shared.ready) WBWaitForRegistry();
|
||||
NSArray *proxies = WBRegistry.shared.proxies;
|
||||
if (WBRegistry.shared.ready && proxies.count) return proxies;
|
||||
return gOrigAllApplications ? gOrigAllApplications(self, _cmd) : @[];
|
||||
@@ -872,9 +899,6 @@ static void WBHookDetailReload(id self, SEL _cmd)
|
||||
static void WBHookLoad(id self, SEL _cmd)
|
||||
{
|
||||
gAppsTableViewController = self;
|
||||
if (gReadySemaphore && !WBRegistry.shared.ready) {
|
||||
dispatch_semaphore_wait(gReadySemaphore, dispatch_time(DISPATCH_TIME_NOW, 120 * NSEC_PER_SEC));
|
||||
}
|
||||
gOrigLoad(self, _cmd);
|
||||
}
|
||||
|
||||
@@ -1467,7 +1491,7 @@ static void WBInstallHooks(void)
|
||||
method_setImplementation(didFinish, (IMP)WBHookDidFinishLaunching);
|
||||
}
|
||||
|
||||
gReadySemaphore = dispatch_semaphore_create(0);
|
||||
gReadyCondition = [NSCondition new];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"WBAppSizeDidUpdate" object:nil queue:NSOperationQueue.mainQueue usingBlock:^(NSNotification *note) {
|
||||
if (gReloadScheduled) return;
|
||||
gReloadScheduled = YES;
|
||||
@@ -1661,7 +1685,6 @@ static void WBRunDebugRefresh(void)
|
||||
static void WBStartPreparation(void)
|
||||
{
|
||||
if (gPreparing || gPrepared) return;
|
||||
gPreparing = YES;
|
||||
|
||||
UIWindow *window = UIApplication.sharedApplication.keyWindow;
|
||||
if (!window) {
|
||||
@@ -1673,25 +1696,58 @@ static void WBStartPreparation(void)
|
||||
}
|
||||
}
|
||||
UIViewController *root = window.rootViewController;
|
||||
if (root && !gProgressController) {
|
||||
if (!root) {
|
||||
// On a cold launch the window/root view may not exist yet. Wait for it
|
||||
// instead of running the preparation with no visible progress sheet.
|
||||
if (!gWaitingForRoot && CFAbsoluteTimeGetCurrent() - gLaunchStarted < 10) {
|
||||
gWaitingForRoot = YES;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
||||
gWaitingForRoot = NO;
|
||||
WBStartPreparation();
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!gWaitingForRoot) {
|
||||
// Last-resort fallback: start even without a presenter.
|
||||
gPreparing = YES;
|
||||
[WBRegistry.shared prepareWithProgress:nil completion:^(BOOL ok, NSString *message) {
|
||||
gPrepared = YES;
|
||||
[gReadyCondition lock];
|
||||
[gReadyCondition broadcast];
|
||||
[gReadyCondition unlock];
|
||||
}];
|
||||
}
|
||||
return;
|
||||
}
|
||||
gPreparing = YES;
|
||||
[root loadViewIfNeeded];
|
||||
UIViewController *presenter = root;
|
||||
while (presenter.presentedViewController) presenter = presenter.presentedViewController;
|
||||
if (!gProgressController) {
|
||||
gProgressController = [WBProgressViewController new];
|
||||
gProgressController.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
[root presentViewController:gProgressController animated:YES completion:nil];
|
||||
[presenter presentViewController:gProgressController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
[WBRegistry.shared prepareWithProgress:^(double fraction, NSString *status) {
|
||||
[gProgressController updateFraction:fraction status:status];
|
||||
} completion:^(BOOL ok, NSString *message) {
|
||||
gPrepared = YES;
|
||||
if (gReadySemaphore) dispatch_semaphore_signal(gReadySemaphore);
|
||||
[gReadyCondition lock];
|
||||
[gReadyCondition broadcast];
|
||||
[gReadyCondition unlock];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (gProgressController) {
|
||||
[gProgressController dismissViewControllerAnimated:YES completion:nil];
|
||||
gProgressController = nil;
|
||||
}
|
||||
if (!ok && message.length) {
|
||||
NSString *detail = message;
|
||||
if ([message containsString:@"App Group"]) {
|
||||
detail = [message stringByAppendingFormat:@"\n\n%@", WBLocalized(@"no_group_hint")];
|
||||
}
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:WBLocalized(@"init_failed")
|
||||
message:message
|
||||
message:detail
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:WBLocalized(@"ok") style:UIAlertActionStyleDefault handler:nil]];
|
||||
UIWindow *keyWindow = UIApplication.sharedApplication.keyWindow;
|
||||
@@ -1711,6 +1767,7 @@ __attribute__((constructor))
|
||||
static void WBHookInit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
gLaunchStarted = CFAbsoluteTimeGetCurrent();
|
||||
WBInstallHooks();
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification
|
||||
|
||||
Reference in new issue
Block a user