3

如果我在 iOS 12 设备(不使用 UIScene)和 AirPlay Mirror 上编译到我的 Apple TV,则应用程序会按预期镜像到电视上。

在 iOS 13 设备上,它似乎将其视为外部显示器,并对其进行格式化以适应屏幕(但我无法控制它)。

我更喜欢只是镜像它的旧功能。

如何在 iOS 13 上完成镜像?我在文档中四处寻找:

application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration

并且在其中UISceneConfiguration有一个role属性(UISceneSession.Role.windowExternalDisplay当我尝试 AirPlay Mirror 时它有),但它似乎没有任何价值,例如UISceneSession.Role.windowMirror.

4

4 回答 4

5

我一直在玩镜像和外部显示器,只有代码/设置的正确组合存在各种可能性,但某些功能似乎不可能。

在 iOS 13 下(使用 iOS 13 的 Base SDK 构建的应用程序),您可以将应用程序镜像到外部显示器上。但是使这项工作可以防止您的应用程序在外部显示器上显示不同的内容。基本上,您的应用程序仅镜像或仅显示外部显示器的独特场景。

如果您希望只镜像您的应用程序,请确保以下内容:

  1. application(_:configurationForConnecting:options:)从您的 App Delegate 中删除。
  2. 在Info.plist中,确保“Application Scene Manifest”的“Scene Configuration”部分下“External Display Session Role”没有条目。

如果这两件事都不是您的应用程序的一部分,那么当您在 iOS 设备上激活屏幕镜像时,您的应用程序将简单地镜像到任何外部屏幕。

于 2019-10-24T00:31:58.403 回答
3

我自己也遇到了这个问题。我的解决方案实际上来自我的UIWindowSceneDelegate班级。

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        // External displays should not get assigned a window. When a window isn't assigned, the default behavior is mirroring.
        guard session.role != .windowExternalDisplay else { return }
        /* the rest of your setup */
    }

当您不分配窗口时,镜像似乎成为默认选项。在此更改之前,我的外部显示器(屏幕镜像)拥有自己独特的 UIWindow 实例。

我没有在任何地方看到这个文档,而且它不直观。正因为如此,我有点担心它将来会破裂。

希望它仍然有帮助。

于 2020-06-22T20:13:30.373 回答
1

我发现使用Objective-C实现,你可以通过返回来实现屏幕镜像nil行为 application:configurationForConnectingSceneSession:options:

- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
    if (connectingSceneSession.role == UIWindowSceneSessionRoleExternalDisplay) {
        return nil;
    }
    UISceneConfiguration *configuration = [[UISceneConfiguration alloc] initWithName:@"Main" sessionRole:connectingSceneSession.role];
    configuration.storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    configuration.delegateClass = [SceneDelegate class];
    configuration.sceneClass = [UIWindowScene class];
    return configuration;
}

请注意,这不是记录在案的方式,将来可能会中断。

编辑:在 Swift 中,您可以通过方法调配来实现:

@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {

    override init() {
        _ = AppDelegate.performSceneConfigurationSwizzle
        super.init()
    }

    private static let performSceneConfigurationSwizzle: Void = {
        method_exchangeImplementations(
            class_getInstanceMethod(AppDelegate.self, #selector(AppDelegate.application(_:configurationForConnecting:options:)))!,
            class_getInstanceMethod(AppDelegate.self, #selector(AppDelegate.swizzle_application(_:configurationForConnecting:options:)))!
        )
    }()

    @objc func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        fatalError("Should never reach.")
    }

    @objc private func swizzle_application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration? {
        if connectingSceneSession.role == .windowExternalDisplay {
            return nil
        }
        // build scene configuration as usual…
    }
}
于 2020-03-31T03:45:26.830 回答
0

而不是在 iOS 13 中实现 AppDelegate 场景配置方法:

@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    let configuration = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    configuration.delegateClass = SceneDelegate.self
    return configuration
}

我改为使用 Info.plist 变体(并删除了上面的代码),您可以在 Info.plist 中有效地指定上述所有内容。(对于 Info.plist 文件中预期的最新版本,只需在 Xcode 中创建一个新项目并从新的 Info.plist 文件中复制内容以获得Application Scene Manifest密钥)。

它现在可以完美运行,AirPlay Mirror 可以按预期进行镜像。我确实尝试过将其更改rolewindowApplicationiOS 似乎对 Info.plist 变体所做的那样,但它仍然不起作用。

于 2019-10-24T00:29:51.330 回答