mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
feat: add support for multiple scenes and handle URL contexts in iOS 13+ (#1889)
This commit is contained in:
@@ -46,6 +46,7 @@ set(SOURCES ${SOURCES}
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/AmneziaSceneDelegateHooks.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,17 +32,41 @@
|
|||||||
<false/>
|
<false/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>AmneziaVPNLaunchScreen</string>
|
<string>AmneziaVPNLaunchScreen</string>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<true/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneClassName</key>
|
||||||
|
<string>UIWindowScene</string>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>Default Configuration</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>QIOSWindowSceneDelegate</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<array/>
|
<array/>
|
||||||
<key>UIRequiresFullScreen</key>
|
<key>UIRequiresFullScreen</key>
|
||||||
<true/>
|
<false/>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array/>
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
<key>UIUserInterfaceStyle</key>
|
<key>UIUserInterfaceStyle</key>
|
||||||
<string>Light</string>
|
<string>Light</string>
|
||||||
<key>com.wireguard.ios.app_group_id</key>
|
<key>com.wireguard.ios.app_group_id</key>
|
||||||
|
|||||||
82
client/platforms/ios/AmneziaSceneDelegateHooks.mm
Normal file
82
client/platforms/ios/AmneziaSceneDelegateHooks.mm
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#include <dispatch/dispatch.h>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "ios_controller.h"
|
||||||
|
|
||||||
|
using SceneOpenURLContexts = void (*)(id, SEL, UIScene *, NSSet<UIOpenURLContext *> *);
|
||||||
|
|
||||||
|
static SceneOpenURLContexts g_originalSceneOpenURLContexts = nullptr;
|
||||||
|
|
||||||
|
static void amnezia_handleURL(NSURL *url)
|
||||||
|
{
|
||||||
|
if (!url || !url.isFileURL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString filePath(url.path.UTF8String);
|
||||||
|
if (filePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
if (filePath.contains("backup")) {
|
||||||
|
IosController::Instance()->importBackupFromOutside(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray data = file.readAll();
|
||||||
|
IosController::Instance()->importConfigFromOutside(QString::fromUtf8(data));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amnezia_scene_openURLContexts(id self, SEL _cmd, UIScene *scene, NSSet<UIOpenURLContext *> *contexts)
|
||||||
|
{
|
||||||
|
if (g_originalSceneOpenURLContexts) {
|
||||||
|
g_originalSceneOpenURLContexts(self, _cmd, scene, contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contexts || contexts.count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@available(iOS 13.0, *)) {
|
||||||
|
for (UIOpenURLContext *context in contexts) {
|
||||||
|
amnezia_handleURL(context.URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface AmneziaSceneDelegateHooks : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AmneziaSceneDelegateHooks
|
||||||
|
|
||||||
|
+ (void)load
|
||||||
|
{
|
||||||
|
Class cls = objc_getClass("QIOSWindowSceneDelegate");
|
||||||
|
if (!cls) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEL selector = @selector(scene:openURLContexts:);
|
||||||
|
Method method = class_getInstanceMethod(cls, selector);
|
||||||
|
if (method) {
|
||||||
|
g_originalSceneOpenURLContexts = reinterpret_cast<SceneOpenURLContexts>(method_getImplementation(method));
|
||||||
|
method_setImplementation(method, reinterpret_cast<IMP>(amnezia_scene_openURLContexts));
|
||||||
|
} else {
|
||||||
|
const char *types = "v@:@@";
|
||||||
|
class_addMethod(cls, selector, reinterpret_cast<IMP>(amnezia_scene_openURLContexts), types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -29,12 +29,46 @@ const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
|||||||
|
|
||||||
#if !MACOS_NE
|
#if !MACOS_NE
|
||||||
static UIViewController* getViewController() {
|
static UIViewController* getViewController() {
|
||||||
NSArray *windows = [[UIApplication sharedApplication]windows];
|
UIApplication *application = [UIApplication sharedApplication];
|
||||||
for (UIWindow *window in windows) {
|
|
||||||
if (window.isKeyWindow) {
|
if (@available(iOS 13.0, *)) {
|
||||||
|
for (UIScene *scene in application.connectedScenes) {
|
||||||
|
if (scene.activationState != UISceneActivationStateForegroundActive) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||||
|
|
||||||
|
for (UIWindow *window in windowScene.windows) {
|
||||||
|
if (window.isKeyWindow && window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in windowScene.windows) {
|
||||||
|
if (!window.isHidden && window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in application.windows) {
|
||||||
|
if (window.isKeyWindow && window.rootViewController) {
|
||||||
return window.rootViewController;
|
return window.rootViewController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in application.windows) {
|
||||||
|
if (window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user