diff --git a/packages/share_plus/share_plus/example/ios/RunnerTests/RunnerTests.swift b/packages/share_plus/share_plus/example/ios/RunnerTests/RunnerTests.swift index 86a7c3b1b6..107c13d6f3 100644 --- a/packages/share_plus/share_plus/example/ios/RunnerTests/RunnerTests.swift +++ b/packages/share_plus/share_plus/example/ios/RunnerTests/RunnerTests.swift @@ -1,12 +1,85 @@ import Flutter import UIKit import XCTest +import share_plus class RunnerTests: XCTestCase { - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + @MainActor + func testUriSharePreservesSubject() throws { + let controller = try shareUri(subject: "Subject for Mail") + XCTAssertEqual(controller.value(forKey: "subject") as? String, "Subject for Mail") } + @MainActor + func testUriShareUsesTitleBeforeLegacySubject() throws { + let controller = try shareUri(subject: "Legacy subject", title: "Share title") + XCTAssertEqual(controller.value(forKey: "subject") as? String, "Share title") + } + + @MainActor + func testUriShareWithoutSubject() throws { + let controller = try shareUri() + XCTAssertNil(controller.value(forKey: "subject")) + } + + @MainActor + private func shareUri(subject: String? = nil, title: String? = nil) throws + -> UIActivityViewController + { + let scene = try XCTUnwrap(UIApplication.shared.connectedScenes.first as? UIWindowScene) + let window = try XCTUnwrap(scene.windows.first(where: { $0.isKeyWindow })) + let previousController = window.rootViewController + let presenter = RecordingViewController() + window.rootViewController = presenter + defer { window.rootViewController = previousController } + + let engine = RecordingEngine(name: "share-plus-subject-test") + let registrar = try XCTUnwrap(engine.registrar(forPlugin: "share-plus-subject-test")) + FPPSharePlusPlugin.register(with: registrar) + let handler = try XCTUnwrap(engine.recorder.handler) + var arguments: [String: Any] = [ + "uri": "https://example.test/link", + "originX": 1.0, "originY": 1.0, "originWidth": 20.0, "originHeight": 20.0, + ] + if let subject { arguments["subject"] = subject } + if let title { arguments["title"] = title } + let call = FlutterMethodCall(methodName: "share", arguments: arguments) + handler(FlutterStandardMethodCodec.sharedInstance().encode(call)) { _ in + XCTFail("Sharing should wait for the activity to complete") + } + return try XCTUnwrap(presenter.activityController) + } +} + +private final class RecordingEngine: FlutterEngine { + let recorder = RecordingMessenger() + + override var binaryMessenger: FlutterBinaryMessenger { recorder } +} + +private final class RecordingMessenger: NSObject, FlutterBinaryMessenger { + var handler: FlutterBinaryMessageHandler? + + func send(onChannel channel: String, message: Data?) {} + func send(onChannel channel: String, message: Data?, binaryReply callback: FlutterBinaryReply?) {} + func cleanUpConnection(_ connection: FlutterBinaryMessengerConnection) {} + + func setMessageHandlerOnChannel( + _ channel: String, binaryMessageHandler handler: FlutterBinaryMessageHandler? + ) -> FlutterBinaryMessengerConnection { + if channel == "dev.fluttercommunity.plus/share" { self.handler = handler } + return 1 + } +} + +private final class RecordingViewController: UIViewController { + var activityController: UIActivityViewController? + + override func present( + _ viewControllerToPresent: UIViewController, animated flag: Bool, + completion: (() -> Void)? = nil + ) { + activityController = viewControllerToPresent as? UIActivityViewController + } } diff --git a/packages/share_plus/share_plus/ios/share_plus/Sources/share_plus/FPPSharePlusPlugin.m b/packages/share_plus/share_plus/ios/share_plus/Sources/share_plus/FPPSharePlusPlugin.m index 42a05468b2..66c7c24621 100644 --- a/packages/share_plus/share_plus/ios/share_plus/Sources/share_plus/FPPSharePlusPlugin.m +++ b/packages/share_plus/share_plus/ios/share_plus/Sources/share_plus/FPPSharePlusPlugin.m @@ -363,6 +363,7 @@ + (void)registerWithRegistrar:(NSObject *)registrar { if (uri) { [self shareUri:uri + subject:shareTitle excludedActivityTypes:excludedActivityTypes withController:topViewController atSource:originRect @@ -458,13 +459,14 @@ + (void)share:(NSArray *)shareItems } + (void)shareUri:(NSString *)uri + subject:(NSString *)subject excludedActivityTypes:(NSArray *)excludedActivityTypes withController:(UIViewController *)controller atSource:(CGRect)origin toResult:(FlutterResult)result { NSURL *data = [NSURL URLWithString:uri]; [self share:@[ data ] - withSubject:nil + withSubject:subject excludedActivityTypes:excludedActivityTypes withController:controller atSource:origin