diff --git a/packages/quick_actions/quick_actions_ios/CHANGELOG.md b/packages/quick_actions/quick_actions_ios/CHANGELOG.md index 31fe43832d2f..bded35478899 100644 --- a/packages/quick_actions/quick_actions_ios/CHANGELOG.md +++ b/packages/quick_actions/quick_actions_ios/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.2 +* Migrates remaining components to Swift and removes all Objective-C settings. * Migrates `RunnerUITests` to Swift. ## 1.0.1 diff --git a/packages/quick_actions/quick_actions_ios/example/ios/Podfile b/packages/quick_actions/quick_actions_ios/example/ios/Podfile index b52805241c18..3924e59aa0f9 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/Podfile +++ b/packages/quick_actions/quick_actions_ios/example/ios/Podfile @@ -31,7 +31,6 @@ target 'Runner' do flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths - pod 'OCMock', '~> 3.9.1' end end diff --git a/packages/quick_actions/quick_actions_ios/example/ios/Runner.xcodeproj/project.pbxproj b/packages/quick_actions/quick_actions_ios/example/ios/Runner.xcodeproj/project.pbxproj index c853a197ca9b..f5b708bbb54b 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/quick_actions/quick_actions_ios/example/ios/Runner.xcodeproj/project.pbxproj @@ -16,9 +16,12 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E092A7ED28D10802005C7F67 /* MockMethodChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */; }; + E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */; }; + E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */; }; + E092A7F428D110B3005C7F67 /* DefaultShortcutItemParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */; }; E092A7F628D128EB005C7F67 /* RunnerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F528D128EB005C7F67 /* RunnerUITests.swift */; }; - E0C09C29289C729D00E6977E /* FLTQuickActionsPluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C09C28289C729D00E6977E /* FLTQuickActionsPluginTests.m */; }; - E0C09C32289DBFCA00E6977E /* FLTShortcutStateManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C09C31289DBFCA00E6977E /* FLTShortcutStateManagerTests.m */; }; + E0A075D529147FE200329BAE /* MockShortcutItemParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -75,9 +78,12 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9D27FE1F0F21D4D47DDA16DE /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; C35AD3650AB6BF850E016715 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockMethodChannel.swift; sourceTree = ""; }; + E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionsPluginTests.swift; sourceTree = ""; }; + E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemProvider.swift; sourceTree = ""; }; + E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultShortcutItemParserTests.swift; sourceTree = ""; }; E092A7F528D128EB005C7F67 /* RunnerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerUITests.swift; sourceTree = ""; }; - E0C09C28289C729D00E6977E /* FLTQuickActionsPluginTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTQuickActionsPluginTests.m; sourceTree = ""; }; - E0C09C31289DBFCA00E6977E /* FLTShortcutStateManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTShortcutStateManagerTests.m; sourceTree = ""; }; + E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemParser.swift; sourceTree = ""; }; F0609304FBCAEC2289164BD5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -111,9 +117,10 @@ 33E20B3326EFCDFC00A4A191 /* RunnerTests */ = { isa = PBXGroup; children = ( + E092A7F228D10908005C7F67 /* Mocks */, 33E20B3626EFCDFC00A4A191 /* Info.plist */, - E0C09C31289DBFCA00E6977E /* FLTShortcutStateManagerTests.m */, - E0C09C28289C729D00E6977E /* FLTQuickActionsPluginTests.m */, + E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */, + E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */, ); path = RunnerTests; sourceTree = ""; @@ -205,6 +212,16 @@ name = Pods; sourceTree = ""; }; + E092A7F228D10908005C7F67 /* Mocks */ = { + isa = PBXGroup; + children = ( + E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */, + E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */, + E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */, + ); + path = Mocks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -277,6 +294,7 @@ TargetAttributes = { 33E20B3126EFCDFC00A4A191 = { CreatedOnToolsVersion = 12.5; + LastSwiftMigration = 1330; TestTargetID = 97C146ED1CF9000F007C117D; }; 686BE82C25E58CCF00862533 = { @@ -416,8 +434,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E0C09C32289DBFCA00E6977E /* FLTShortcutStateManagerTests.m in Sources */, - E0C09C29289C729D00E6977E /* FLTQuickActionsPluginTests.m in Sources */, + E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */, + E092A7ED28D10802005C7F67 /* MockMethodChannel.swift in Sources */, + E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */, + E0A075D529147FE200329BAE /* MockShortcutItemParser.swift in Sources */, + E092A7F428D110B3005C7F67 /* DefaultShortcutItemParserTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -479,6 +500,7 @@ baseConfigurationReference = 9D27FE1F0F21D4D47DDA16DE /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -487,6 +509,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; }; name = Debug; @@ -496,6 +520,7 @@ baseConfigurationReference = 96F949A6B78E2DC62B93C4F8 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -504,6 +529,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; }; name = Release; diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/DefaultShortcutItemParserTests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/DefaultShortcutItemParserTests.swift new file mode 100644 index 000000000000..739f88e90454 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/DefaultShortcutItemParserTests.swift @@ -0,0 +1,67 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import XCTest + +@testable import quick_actions_ios + +class DefaultShortcutItemParserTests: XCTestCase { + + func testParseShortcutItems() { + let rawItem = [ + "type": "SearchTheThing", + "localizedTitle": "Search the thing", + "icon": "search_the_thing.png", + ] + + let expectedItem = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let parser = DefaultShortcutItemParser() + XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem]) + } + + func testParseShortcutItems_noIcon() { + let rawItem: [String: Any] = [ + "type": "SearchTheThing", + "localizedTitle": "Search the thing", + "icon": NSNull(), + ] + + let expectedItem = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: nil, + userInfo: nil) + + let parser = DefaultShortcutItemParser() + XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem]) + } + + func testParseShortcutItems_noType() { + let rawItem = [ + "localizedTitle": "Search the thing", + "icon": "search_the_thing.png", + ] + + let parser = DefaultShortcutItemParser() + XCTAssertEqual(parser.parseShortcutItems([rawItem]), []) + } + + func testParseShortcutItems_noLocalizedTitle() { + let rawItem = [ + "type": "SearchTheThing", + "icon": "search_the_thing.png", + ] + + let parser = DefaultShortcutItemParser() + XCTAssertEqual(parser.parseShortcutItems([rawItem]), []) + } +} diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTQuickActionsPluginTests.m b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTQuickActionsPluginTests.m deleted file mode 100644 index 89651b573822..000000000000 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTQuickActionsPluginTests.m +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import Flutter; -@import quick_actions_ios; -@import XCTest; -#import - -@interface FLTQuickActionsPluginTests : XCTestCase - -@end - -@implementation FLTQuickActionsPluginTests - -- (void)testHandleMethodCall_setShortcutItems { - NSDictionary *rawItem = @{ - @"type" : @"SearchTheThing", - @"localizedTitle" : @"Search the thing", - @"icon" : @"search_the_thing.png", - }; - - FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"setShortcutItems" - arguments:@[ rawItem ]]; - - FLTShortcutStateManager *mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:mockShortcutStateManager]; - XCTestExpectation *resultExpectation = - [self expectationWithDescription:@"result block must be called."]; - [plugin handleMethodCall:call - result:^(id _Nullable result) { - XCTAssertNil(result, @"result block must be called with nil."); - [resultExpectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; - - OCMVerify([mockShortcutStateManager setShortcutItems:@[ rawItem ]]); -} - -- (void)testHandleMethodCall_clearShortcutItems { - FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"clearShortcutItems" - arguments:nil]; - FLTShortcutStateManager *mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:mockShortcutStateManager]; - XCTestExpectation *resultExpectation = - [self expectationWithDescription:@"result block must be called."]; - [plugin handleMethodCall:call - result:^(id _Nullable result) { - XCTAssertNil(result, @"result block must be called with nil."); - [resultExpectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; - OCMVerify([mockShortcutStateManager setShortcutItems:@[]]); -} - -- (void)testHandleMethodCall_getLaunchAction { - FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"getLaunchAction" - arguments:nil]; - - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:OCMClassMock([FLTShortcutStateManager class])]; - XCTestExpectation *resultExpectation = - [self expectationWithDescription:@"result block must be called."]; - [plugin handleMethodCall:call - result:^(id _Nullable result) { - XCTAssertNil(result, @"result block must be called with nil."); - [resultExpectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testHandleMethodCall_nonExistMethods { - FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"nonExist" arguments:nil]; - - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:OCMClassMock([FLTShortcutStateManager class])]; - XCTestExpectation *resultExpectation = - [self expectationWithDescription:@"result must be called."]; - [plugin - handleMethodCall:call - result:^(id _Nullable result) { - XCTAssertEqual(result, FlutterMethodNotImplemented, - @"result block must be called with FlutterMethodNotImplemented"); - [resultExpectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testApplicationPerformActionForShortcutItem { - id mockChannel = OCMClassMock([FlutterMethodChannel class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:mockChannel - shortcutStateManager:OCMClassMock([FLTShortcutStateManager class])]; - - UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] - initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:[UIApplicationShortcutIcon - iconWithTemplateImageName:@"search_the_thing.png"] - userInfo:nil]; - - BOOL actionResult = [plugin application:[UIApplication sharedApplication] - performActionForShortcutItem:item - completionHandler:^(BOOL succeeded){/* no-op */}]; - XCTAssert(actionResult, @"performActionForShortcutItem must return true."); - OCMVerify([mockChannel invokeMethod:@"launch" arguments:item.type]); -} - -- (void)testApplicationDidFinishLaunchingWithOptions_launchWithShortcut { - id mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:mockShortcutStateManager]; - - UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] - initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:[UIApplicationShortcutIcon - iconWithTemplateImageName:@"search_the_thing.png"] - userInfo:nil]; - - BOOL launchResult = [plugin application:[UIApplication sharedApplication] - didFinishLaunchingWithOptions:@{UIApplicationLaunchOptionsShortcutItemKey : item}]; - - XCTAssertFalse(launchResult, - @"didFinishLaunchingWithOptions must return false if launched from shortcut."); -} - -- (void)testApplicationDidFinishLaunchingWithOptions_launchWithoutShortcut { - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:OCMClassMock([FlutterMethodChannel class]) - shortcutStateManager:OCMClassMock([FLTShortcutStateManager class])]; - BOOL launchResult = [plugin application:[UIApplication sharedApplication] - didFinishLaunchingWithOptions:@{}]; - XCTAssertTrue(launchResult, - @"didFinishLaunchingWithOptions must return true if not launched from shortcut."); -} - -- (void)testApplicationDidBecomeActive_launchWithoutShortcut { - id mockChannel = OCMClassMock([FlutterMethodChannel class]); - id mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:mockChannel - shortcutStateManager:mockShortcutStateManager]; - - BOOL launchResult = [plugin application:[UIApplication sharedApplication] - didFinishLaunchingWithOptions:@{}]; - XCTAssertTrue(launchResult, - @"didFinishLaunchingWithOptions must return true if not launched from shortcut."); - [plugin applicationDidBecomeActive:[UIApplication sharedApplication]]; - OCMVerify(never(), [mockChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]); -} - -- (void)testApplicationDidBecomeActive_launchWithShortcut { - id mockChannel = OCMClassMock([FlutterMethodChannel class]); - id mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:mockChannel - shortcutStateManager:mockShortcutStateManager]; - - UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] - initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:[UIApplicationShortcutIcon - iconWithTemplateImageName:@"search_the_thing.png"] - userInfo:nil]; - BOOL launchResult = [plugin application:[UIApplication sharedApplication] - didFinishLaunchingWithOptions:@{UIApplicationLaunchOptionsShortcutItemKey : item}]; - XCTAssertFalse(launchResult, - @"didFinishLaunchingWithOptions must return false if launched from shortcut."); - [plugin applicationDidBecomeActive:[UIApplication sharedApplication]]; - OCMVerify([mockChannel invokeMethod:@"launch" arguments:item.type]); -} - -- (void)testApplicationDidBecomeActive_launchWithShortcut_becomeActiveTwice { - id mockChannel = OCMClassMock([FlutterMethodChannel class]); - id mockShortcutStateManager = OCMClassMock([FLTShortcutStateManager class]); - QuickActionsPlugin *plugin = - [[QuickActionsPlugin alloc] initWithChannel:mockChannel - shortcutStateManager:mockShortcutStateManager]; - - UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] - initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:[UIApplicationShortcutIcon - iconWithTemplateImageName:@"search_the_thing.png"] - userInfo:nil]; - BOOL launchResult = [plugin application:[UIApplication sharedApplication] - didFinishLaunchingWithOptions:@{UIApplicationLaunchOptionsShortcutItemKey : item}]; - XCTAssertFalse(launchResult, - @"didFinishLaunchingWithOptions must return false if launched from shortcut."); - [plugin applicationDidBecomeActive:[UIApplication sharedApplication]]; - [plugin applicationDidBecomeActive:[UIApplication sharedApplication]]; - // shortcut should only be handled once per launch. - OCMVerify(times(1), [mockChannel invokeMethod:@"launch" arguments:item.type]); -} - -@end diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTShortcutStateManagerTests.m b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTShortcutStateManagerTests.m deleted file mode 100644 index 96fbf229e566..000000000000 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/FLTShortcutStateManagerTests.m +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import quick_actions_ios; -@import XCTest; -#import - -@interface FLTShortcutStateManagerTests : XCTestCase -@end - -@implementation FLTShortcutStateManagerTests - -- (void)testSetShortcutItems_shouldSetItem { - id mockApplication = OCMPartialMock([UIApplication sharedApplication]); - OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); - - FLTShortcutStateManager *shortcutStateManager = [[FLTShortcutStateManager alloc] init]; - - NSDictionary *rawItem = @{ - @"type" : @"SearchTheThing", - @"localizedTitle" : @"Search the thing", - @"icon" : @"search_the_thing.png", - }; - - [shortcutStateManager setShortcutItems:@[ rawItem ]]; - - UIApplicationShortcutItem *expectedItem = [[UIApplicationShortcutItem alloc] - initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:[UIApplicationShortcutIcon - iconWithTemplateImageName:@"search_the_thing.png"] - userInfo:nil]; - - OCMVerify([mockApplication setShortcutItems:@[ expectedItem ]]); -} - -- (void)testSetShortcutItems_shouldSetItemWithoutIcon { - id mockApplication = OCMPartialMock([UIApplication sharedApplication]); - OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); - - NSDictionary *rawItem = @{ - @"type" : @"SearchTheThing", - @"localizedTitle" : @"Search the thing", - // Dart's null value is passed to iOS as `NSNull`. - // The key value pair is still present in the dictionary. - @"icon" : [NSNull null], - }; - FLTShortcutStateManager *shortcutStateManager = [[FLTShortcutStateManager alloc] init]; - [shortcutStateManager setShortcutItems:@[ rawItem ]]; - - UIApplicationShortcutItem *expectedItem = - [[UIApplicationShortcutItem alloc] initWithType:@"SearchTheThing" - localizedTitle:@"Search the thing" - localizedSubtitle:nil - icon:nil - userInfo:nil]; - OCMVerify([mockApplication setShortcutItems:@[ expectedItem ]]); -} - -@end diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockMethodChannel.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockMethodChannel.swift new file mode 100644 index 000000000000..b52fa1daec95 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockMethodChannel.swift @@ -0,0 +1,14 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Foundation + +@testable import quick_actions_ios + +final class MockMethodChannel: MethodChannel { + var invokeMethodStub: ((_ methods: String, _ arguments: Any?) -> Void)? = nil + func invokeMethod(_ method: String, arguments: Any?) { + invokeMethodStub?(method, arguments) + } +} diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemParser.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemParser.swift new file mode 100644 index 000000000000..3b5a09653958 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemParser.swift @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Foundation + +@testable import quick_actions_ios + +final class MockShortcutItemParser: ShortcutItemParser { + + var parseShortcutItemsStub: ((_ items: [[String: Any]]) -> [UIApplicationShortcutItem])? = nil + + func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] { + return parseShortcutItemsStub?(items) ?? [] + } +} diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemProvider.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemProvider.swift new file mode 100644 index 000000000000..85477415667e --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/Mocks/MockShortcutItemProvider.swift @@ -0,0 +1,9 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@testable import quick_actions_ios + +final class MockShortcutItemProvider: ShortcutItemProviding { + var shortcutItems: [UIApplicationShortcutItem]? = nil +} diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift new file mode 100644 index 000000000000..268a89ba5a5b --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerTests/QuickActionsPluginTests.swift @@ -0,0 +1,294 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import XCTest + +@testable import quick_actions_ios + +class QuickActionsPluginTests: XCTestCase { + + func testHandleMethodCall_setShortcutItems() { + let rawItem = [ + "type": "SearchTheThing", + "localizedTitle": "Search the thing", + "icon": "search_the_thing.png", + ] + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let call = FlutterMethodCall(methodName: "setShortcutItems", arguments: [rawItem]) + + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let parseShortcutItemsExpectation = expectation( + description: "parseShortcutItems must be called.") + mockShortcutItemParser.parseShortcutItemsStub = { items in + XCTAssertEqual(items as? [[String: String]], [rawItem]) + parseShortcutItemsExpectation.fulfill() + return [item] + } + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertNil(result, "result block must be called with nil.") + resultExpectation.fulfill() + } + XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [item], "Must set shortcut items.") + waitForExpectations(timeout: 1) + } + + func testHandleMethodCall_clearShortcutItems() { + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let call = FlutterMethodCall(methodName: "clearShortcutItems", arguments: nil) + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + mockShortcutItemProvider.shortcutItems = [item] + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertNil(result, "result block must be called with nil.") + resultExpectation.fulfill() + } + + XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [], "Must clear shortcut items.") + waitForExpectations(timeout: 1) + } + + func testHandleMethodCall_getLaunchAction() { + let call = FlutterMethodCall(methodName: "getLaunchAction", arguments: nil) + + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertNil(result, "result block must be called with nil.") + resultExpectation.fulfill() + } + + waitForExpectations(timeout: 1) + } + + func testHandleMethodCall_nonExistMethods() { + let call = FlutterMethodCall(methodName: "nonExist", arguments: nil) + + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let resultExpectation = expectation(description: "result block must be called.") + + plugin.handle(call) { result in + XCTAssertEqual( + result as? NSObject, FlutterMethodNotImplemented, + "result block must be called with FlutterMethodNotImplemented") + resultExpectation.fulfill() + } + + waitForExpectations(timeout: 1) + } + + func testApplicationPerformActionForShortcutItem() { + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let invokeMethodExpectation = expectation(description: "invokeMethod must be called.") + mockChannel.invokeMethodStub = { method, arguments in + XCTAssertEqual(method, "launch") + XCTAssertEqual(arguments as? String, item.type) + invokeMethodExpectation.fulfill() + } + + let actionResult = plugin.application( + UIApplication.shared, + performActionFor: item + ) { success in /* no-op */ } + + XCTAssert(actionResult, "performActionForShortcutItem must return true.") + waitForExpectations(timeout: 1) + } + + func testApplicationDidFinishLaunchingWithOptions_launchWithShortcut() { + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let launchResult = plugin.application( + UIApplication.shared, + didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item]) + XCTAssertFalse( + launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.") + } + + func testApplicationDidFinishLaunchingWithOptions_launchWithoutShortcut() { + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:]) + XCTAssert( + launchResult, "didFinishLaunchingWithOptions must return true if not launched from shortcut.") + } + + func testApplicationDidBecomeActive_launchWithoutShortcut() { + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + mockChannel.invokeMethodStub = { _, _ in + XCTFail("invokeMethod should not be called if launch without shortcut.") + } + + let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:]) + XCTAssert( + launchResult, "didFinishLaunchingWithOptions must return true if not launched from shortcut.") + + plugin.applicationDidBecomeActive(UIApplication.shared) + } + + func testApplicationDidBecomeActive_launchWithShortcut() { + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let invokeMethodExpectation = expectation(description: "invokeMethod must be called.") + mockChannel.invokeMethodStub = { method, arguments in + XCTAssertEqual(method, "launch") + XCTAssertEqual(arguments as? String, item.type) + invokeMethodExpectation.fulfill() + } + + let launchResult = plugin.application( + UIApplication.shared, + didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item]) + + XCTAssertFalse( + launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.") + + plugin.applicationDidBecomeActive(UIApplication.shared) + waitForExpectations(timeout: 1) + } + + func testApplicationDidBecomeActive_launchWithShortcut_becomeActiveTwice() { + let item = UIApplicationShortcutItem( + type: "SearchTheThing", + localizedTitle: "Search the thing", + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"), + userInfo: nil) + + let mockChannel = MockMethodChannel() + let mockShortcutItemProvider = MockShortcutItemProvider() + let mockShortcutItemParser = MockShortcutItemParser() + + let plugin = QuickActionsPlugin( + channel: mockChannel, + shortcutItemProvider: mockShortcutItemProvider, + shortcutItemParser: mockShortcutItemParser) + + let invokeMethodExpectation = expectation(description: "invokeMethod must be called.") + + var invokeMehtodCount = 0 + mockChannel.invokeMethodStub = { method, arguments in + invokeMehtodCount += 1 + invokeMethodExpectation.fulfill() + } + + let launchResult = plugin.application( + UIApplication.shared, + didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item]) + + XCTAssertFalse( + launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.") + + plugin.applicationDidBecomeActive(UIApplication.shared) + waitForExpectations(timeout: 1) + + XCTAssertEqual(invokeMehtodCount, 1, "shortcut should only be handled once per launch.") + } + +} diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.h b/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.h deleted file mode 100644 index 05d0433db6e0..000000000000 --- a/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -NS_ASSUME_NONNULL_BEGIN - -/// Manages the shortcut related states. -@interface FLTShortcutStateManager : NSObject - -/// Sets the list of shortcut items. -/// -/// @param items the list of shortcut items to be parsed and set. -- (void)setShortcutItems:(NSArray *)items API_AVAILABLE(ios(9.0)); -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.m b/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.m deleted file mode 100644 index e39edd2b0f37..000000000000 --- a/packages/quick_actions/quick_actions_ios/ios/Classes/FLTShortcutStateManager.m +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "FLTShortcutStateManager.h" - -@implementation FLTShortcutStateManager - -- (void)setShortcutItems:(NSArray *)items { - NSMutableArray *newShortcuts = [[NSMutableArray alloc] init]; - - for (id item in items) { - UIApplicationShortcutItem *shortcut = [self deserializeShortcutItem:item]; - [newShortcuts addObject:shortcut]; - } - - [UIApplication sharedApplication].shortcutItems = newShortcuts; -} - -- (UIApplicationShortcutItem *)deserializeShortcutItem:(NSDictionary *)serialized { - UIApplicationShortcutIcon *icon = - [serialized[@"icon"] isKindOfClass:[NSNull class]] - ? nil - : [UIApplicationShortcutIcon iconWithTemplateImageName:serialized[@"icon"]]; - return [[UIApplicationShortcutItem alloc] initWithType:serialized[@"type"] - localizedTitle:serialized[@"localizedTitle"] - localizedSubtitle:nil - icon:icon - userInfo:nil]; -} - -@end diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/MethodChannel.swift b/packages/quick_actions/quick_actions_ios/ios/Classes/MethodChannel.swift new file mode 100644 index 000000000000..5d52790dd4b2 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/ios/Classes/MethodChannel.swift @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +/// A channel for platform code to communicate with the Dart code. +protocol MethodChannel { + /// Invokes a method in Dart code. + /// - Parameter method the method name. + /// - Parameter arguments the method arguments. + func invokeMethod(_ method: String, arguments: Any?) +} + +/// A default implementation of the `MethodChannel` protocol. +extension FlutterMethodChannel: MethodChannel {} diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/QuickActionsPlugin.swift b/packages/quick_actions/quick_actions_ios/ios/Classes/QuickActionsPlugin.swift index 26d6d20f8c02..8522c5ff5288 100644 --- a/packages/quick_actions/quick_actions_ios/ios/Classes/QuickActionsPlugin.swift +++ b/packages/quick_actions/quick_actions_ios/ios/Classes/QuickActionsPlugin.swift @@ -15,19 +15,20 @@ public final class QuickActionsPlugin: NSObject, FlutterPlugin { registrar.addApplicationDelegate(instance) } - private let channel: FlutterMethodChannel - private let shortcutStateManager: FLTShortcutStateManager + private let channel: MethodChannel + private let shortcutItemProvider: ShortcutItemProviding + private let shortcutItemParser: ShortcutItemParser /// The type of the shortcut item selected when launching the app. private var launchingShortcutType: String? = nil - // TODO: (hellohuanlin) remove `@objc` attribute and make it non-public after migrating tests to Swift. - @objc - public init( - channel: FlutterMethodChannel, - shortcutStateManager: FLTShortcutStateManager = FLTShortcutStateManager() + init( + channel: MethodChannel, + shortcutItemProvider: ShortcutItemProviding = UIApplication.shared, + shortcutItemParser: ShortcutItemParser = DefaultShortcutItemParser() ) { self.channel = channel - self.shortcutStateManager = shortcutStateManager + self.shortcutItemProvider = shortcutItemProvider + self.shortcutItemParser = shortcutItemParser } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -35,10 +36,10 @@ public final class QuickActionsPlugin: NSObject, FlutterPlugin { case "setShortcutItems": // `arguments` must be an array of dictionaries let items = call.arguments as! [[String: Any]] - shortcutStateManager.setShortcutItems(items) + shortcutItemProvider.shortcutItems = shortcutItemParser.parseShortcutItems(items) result(nil) case "clearShortcutItems": - shortcutStateManager.setShortcutItems([]) + shortcutItemProvider.shortcutItems = [] result(nil) case "getLaunchAction": result(nil) diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemParser.swift b/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemParser.swift new file mode 100644 index 000000000000..0945b4a386f8 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemParser.swift @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import UIKit + +/// A parser that parses an array of raw shortcut items. +protocol ShortcutItemParser { + + /// Parses an array of raw shortcut items into an array of UIApplicationShortcutItems + /// + /// - Parameter items an array of raw shortcut items to be parsed. + /// - Returns an array of parsed shortcut items to be set. + /// + func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] +} + +/// A default implementation of the `ShortcutItemParser` protocol. +final class DefaultShortcutItemParser: ShortcutItemParser { + + func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] { + return items.compactMap { deserializeShortcutItem(with: $0) } + } + + private func deserializeShortcutItem(with serialized: [String: Any]) -> UIApplicationShortcutItem? + { + guard + let type = serialized["type"] as? String, + let localizedTitle = serialized["localizedTitle"] as? String + else { + return nil + } + + let icon = (serialized["icon"] as? String).map { + UIApplicationShortcutIcon(templateImageName: $0) + } + + // type and localizedTitle are required. + return UIApplicationShortcutItem( + type: type, + localizedTitle: localizedTitle, + localizedSubtitle: nil, + icon: icon, + userInfo: nil) + } +} diff --git a/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemProviding.swift b/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemProviding.swift new file mode 100644 index 000000000000..e8854863bf95 --- /dev/null +++ b/packages/quick_actions/quick_actions_ios/ios/Classes/ShortcutItemProviding.swift @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import UIKit + +/// Provides the capability to get and set the app's home screen shortcut items. +protocol ShortcutItemProviding: AnyObject { + + /// An array of shortcut items for home screen. + var shortcutItems: [UIApplicationShortcutItem]? { get set } +} + +/// A default implementation of the `ShortcutItemProviding` protocol. +extension UIApplication: ShortcutItemProviding {} diff --git a/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios.podspec b/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios.podspec index d8090caa8ef6..a6fff92025b2 100644 --- a/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios.podspec +++ b/packages/quick_actions/quick_actions_ios/ios/quick_actions_ios.podspec @@ -15,12 +15,11 @@ Downloaded by pub (not CocoaPods). s.source = { :http => 'https://github.com/flutter/plugins/tree/main/packages/quick_actions' } s.documentation_url = 'https://pub.dev/packages/quick_actions' s.swift_version = '5.0' - s.source_files = 'Classes/**/*.{h,m,swift}' + s.source_files = 'Classes/**/*.swift' s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', } - s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' s.platform = :ios, '9.0' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } diff --git a/packages/quick_actions/quick_actions_ios/pubspec.yaml b/packages/quick_actions/quick_actions_ios/pubspec.yaml index f01ae4aed9c3..6e7fb43dd7ed 100644 --- a/packages/quick_actions/quick_actions_ios/pubspec.yaml +++ b/packages/quick_actions/quick_actions_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions_ios description: An implementation for the iOS platform of the Flutter `quick_actions` plugin. repository: https://github.com/flutter/plugins/tree/main/packages/quick_actions/quick_actions_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 1.0.1 +version: 1.0.2 environment: sdk: ">=2.15.0 <3.0.0"