[quick_actions]Migrates all remaining components to Swift, and deprecate OCMock (#6597)
* [quick_actions]migrate shortcut state manager, deprecate OCMock and use POP
* remove objc proj settings
* rename shortcut state manager
* bump version
* run swift-format
* nit
* remove public_header_files
* use shortcut item parser instead of shortcut state manager
* some nit
* rename AppShortcutControlling to ShortcutItemProviding
* nit
* do not crash if no type or title
* update license
diff --git a/packages/quick_actions/quick_actions_ios/CHANGELOG.md b/packages/quick_actions/quick_actions_ios/CHANGELOG.md
index 31fe438..bded354 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 b528052..3924e59 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 @@
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 c853a19..f5b708b 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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
+ E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionsPluginTests.swift; sourceTree = "<group>"; };
+ E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemProvider.swift; sourceTree = "<group>"; };
+ E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultShortcutItemParserTests.swift; sourceTree = "<group>"; };
E092A7F528D128EB005C7F67 /* RunnerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerUITests.swift; sourceTree = "<group>"; };
- E0C09C28289C729D00E6977E /* FLTQuickActionsPluginTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTQuickActionsPluginTests.m; sourceTree = "<group>"; };
- E0C09C31289DBFCA00E6977E /* FLTShortcutStateManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTShortcutStateManagerTests.m; sourceTree = "<group>"; };
+ E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemParser.swift; sourceTree = "<group>"; };
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 = "<group>"; };
/* 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 = "<group>";
@@ -205,6 +212,16 @@
name = Pods;
sourceTree = "<group>";
};
+ E092A7F228D10908005C7F67 /* Mocks */ = {
+ isa = PBXGroup;
+ children = (
+ E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */,
+ E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */,
+ E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */,
+ );
+ path = Mocks;
+ sourceTree = "<group>";
+ };
/* 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 0000000..739f88e
--- /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 89651b5..0000000
--- 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 <OCMock/OCMock.h>
-
-@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 96fbf22..0000000
--- 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 <OCMock/OCMock.h>
-
-@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 0000000..b52fa1d
--- /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 0000000..3b5a096
--- /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 0000000..8547741
--- /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 0000000..268a89b
--- /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 05d0433..0000000
--- 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 <Foundation/Foundation.h>
-
-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 e39edd2..0000000
--- 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<UIApplicationShortcutItem *> *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 0000000..5d52790
--- /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 26d6d20..8522c5f 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 @@
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 @@
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 0000000..0945b4a
--- /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 0000000..e885486
--- /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 d8090ca..a6fff92 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 @@
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 f01ae4a..6e7fb43 100644
--- a/packages/quick_actions/quick_actions_ios/pubspec.yaml
+++ b/packages/quick_actions/quick_actions_ios/pubspec.yaml
@@ -2,7 +2,7 @@
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"