Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[quick_actions]Migrates all remaining components to Swift, and deprecate OCMock #6597

Conversation

hellohuanlin
Copy link
Contributor

@hellohuanlin hellohuanlin commented Oct 20, 2022

This PR completes the Swift migration for quick_actions plugin. The main part is to migrate FLTShortcutStateManager using POP. We defined the following new types:

  • MethodChannel protocol (to which FlutterMethodChannel conforms)
  • AppShortcutControlling protocol (to which UIApplication conforms)
  • ShortcutItemParser protocol

The above naming follows the proposal "Swift POP naming convention".

Note that we have to migrate FLTQuickActionsPluginTests too in this PR, because this test depends on ShortcutStateManaging, which is non-objc type that OCMock does not support.

If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.

flutter/flutter#108750

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the relevant style guides and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/plugins repo does use dart format.)
  • I signed the CLA.
  • The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.
  • I updated CHANGELOG.md to add a description of the change, following repository CHANGELOG style.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

}

/// A default implementation of the `MethodChannel` protocol.
extension FlutterMethodChannel: MethodChannel {}
Copy link
Contributor Author

@hellohuanlin hellohuanlin Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I put this extension in the same file as the protocol. Alternatively we can also use separate files and I am ok either way.

More details discussed in Rule 3(b) of the Swift POP naming convention proposal. Feel free to leave any comments.

@hellohuanlin hellohuanlin changed the title [quick_actions]Migrates remaining classes to Swift, and deprecate OCMock [quick_actions]Migrates all remaining components to Swift, and deprecate OCMock Oct 20, 2022
@hellohuanlin hellohuanlin marked this pull request as ready for review October 20, 2022 23:48
}

/// A default implementation of `ShortcutStateManaging` protocol.
final class DefaultShortcutStateManager: ShortcutStateManaging {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: i put this class in the same file as the protocol, but also ok to use separate files.

More details discussed in Rule 3(b) of the Swift POP naming convention proposal. Feel free to leave any comments.


// type and localizedTitle are required.
return UIApplicationShortcutItem(
type: serialized["type"] as! String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should not let this plugin crash the production app? Maybe use Assert to crash debug app and return nil if either serialized["type"] or serialized["localizedTitle"] is nil in release.

Does the original Objective-C API crashes the App if type or localizedTitle is nil? If so, I'm ok with keep the same behavior and follow up with a fix.

Copy link
Contributor Author

@hellohuanlin hellohuanlin Oct 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the original Objective-C API crashes the App if type or localizedTitle is nil?

I think so, the API is non-null (and that's why it bridges to non-null String in Swift): https://developer.apple.com/documentation/uikit/uiapplicationshortcutitem/1623372-initwithtype?language=objc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopting pigeon would solve this.

Copy link
Member

@jmagman jmagman Nov 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the Objective-C API actually crash if you pass in nil though? A lot of Objective-C APIs that predate nullability do handle nils under the covers, especially since most implementation files aren't wrapped in NS_ASSUME_NULL to catch the error in analysis. Ideally passing in the wrong types would give an actionable error, but at the least this should not introduce a new crash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Let me try it out.

The dart counterpart also guarantees that this is never null though. So it likely doesn't matter anyways.

Copy link
Contributor Author

@hellohuanlin hellohuanlin Nov 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried it out - indeed the objc API did not crash - instead it just ignores it.

@hellohuanlin
Copy link
Contributor Author

friendly ping

import UIKit

/// Manages the shortcut related states.
protocol ShortcutStateManaging {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense for there to be a var shortcutItems: [UIApplicationShortcutItem]? { get set } protocol as well as this one? It looks like DefaultShortcutStateManager could easily implement ShortcutItemServicing instead by exposing service.shortcutItems.

Copy link
Contributor Author

@hellohuanlin hellohuanlin Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The var shortcutItems: [UIApplicationShortcutItem]? { get set } protocol is just an abstraction to stub UIApplication. The ShortcutStateManager has extra parsing logic. So it is better not to combine these 2.

An alternative way is to define a ShortcutItemParser, like this:

protocol ShortcutItemParser {
  func parseItems(_ items: [[String, Any]]) -> [UIApplicationShortcutItem]
}

This will make the dependency DAG more "flat". Let me try and see how it goes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated ShortcutStateManager to ShortcutItemParser, and renamed ShortcutItemServicing to AppShortcutControlling.

The benefit is simpler and more flat dependency tree: Now the QuickActionsPlugin depends on both ShortcutItemParser and AppShortcutControlling, and these 2 subcomponents do not depend on each other anymore.

PTAL thx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we still want to have a separate AppShortcutControlling protocol, so that we can stub out the UIApplication.default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ShortcutItemParser SGTM.

But AppShortcutControlling isn't a capability in the sense the docs mean, in that setting this shortcutItems collection is not operating on the "implementing" UIApplication, it's more mutating it. Like the example ProgressReporting would be reporting on the progress of the thing implementing the protocol.

In addition, "AppShortcutControlling" doesn't exactly make sense in English. How about ShortcutItemProvider? At the end of the day Swift's naming guidance is purposely very loosey, we should name it in a way that describes what it does, and also makes sense in English.

Copy link
Contributor Author

@hellohuanlin hellohuanlin Nov 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, Provide sounds like it only provides something, with only getter and no setters (e.g. AgeProviding in the style guide).

How about AppShortcutManaging? it's setting a collection, but also making iOS to update the springboard shortcuts. So it feels like performing an action, rather than just a collection holder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm circling back on this - i think i am fine with the Provider name (it's not ideal, as explained above), but i can't think of a better name.

Though we want Providing for protocol name, since it's a capability to provide something (similar to NameProviding and AgeProviding in our style guide. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! Thanks for iterating on this with me!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to ShortcutItemProviding (unless @cyanglaz or @stuartmorgan can think of a better name?)


// type and localizedTitle are required.
return UIApplicationShortcutItem(
type: serialized["type"] as! String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopting pigeon would solve this.

@hellohuanlin hellohuanlin force-pushed the quick_actions_migrate_shortcut_state_manager_to_swift branch 2 times, most recently from b48938a to 1295feb Compare November 3, 2022 23:32
/// Services `UIApplicationShortcutItem`s.
protocol ShortcutItemServicing: AnyObject {
/// Controlls app's shortcut behavior.
protocol AppShortcutControlling: AnyObject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need AnyObject?

Copy link
Contributor Author

@hellohuanlin hellohuanlin Nov 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnyObject scopes this protocol to reference types (classes). It prevents any value types (enums & structs) to conform to it.

Since this is injected dependency with no value semantics, we want to scope it to reference types. See the NOTE below:

class QuickActionsPlugin {
  // NOTE: If we remove `AnyObject`, we have to use `var` here. 
  private let controller: AppShortcutControlling 

  func foo() {
    controller.shortcutItems = [] // mutate here
  }
}

import UIKit

/// Manages the shortcut related states.
protocol ShortcutStateManaging {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ShortcutItemParser SGTM.

But AppShortcutControlling isn't a capability in the sense the docs mean, in that setting this shortcutItems collection is not operating on the "implementing" UIApplication, it's more mutating it. Like the example ProgressReporting would be reporting on the progress of the thing implementing the protocol.

In addition, "AppShortcutControlling" doesn't exactly make sense in English. How about ShortcutItemProvider? At the end of the day Swift's naming guidance is purposely very loosey, we should name it in a way that describes what it does, and also makes sense in English.

@hellohuanlin hellohuanlin force-pushed the quick_actions_migrate_shortcut_state_manager_to_swift branch from 6d5c871 to fd9968e Compare November 14, 2022 20:32
@hellohuanlin
Copy link
Contributor Author

@jmagman @cyanglaz friendly ping

Copy link
Contributor

@cyanglaz cyanglaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hellohuanlin hellohuanlin force-pushed the quick_actions_migrate_shortcut_state_manager_to_swift branch from de2266a to 76d835e Compare November 15, 2022 19:07
@hellohuanlin hellohuanlin added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 18, 2022
@auto-submit auto-submit bot merged commit 89cbf74 into flutter:main Nov 18, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 18, 2022
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Nov 18, 2022
* 19673b341 [camera]: Bump camerax_version (flutter/plugins#6709)

* b8282424e [gh_actions]: Bump ossf/scorecard-action from 2.0.4 to 2.0.6 (flutter/plugins#6610)

* 2ba4c0a70 [file_selector] Add getDirectoryPaths method to the file_selector_platform_interface. (flutter/plugins#6572)

* 89cbf74c8 [quick_actions]Migrates all remaining components to Swift, and deprecate OCMock (flutter/plugins#6597)

* 51d084453 [quick_actions] Fix Android integration test flake (flutter/plugins#6688)

* b2fe01bc0 [google_sign_in] Correctly passes `serverClientId` to native libs (flutter/plugins#6691)
adam-harwood pushed a commit to adam-harwood/flutter_plugins that referenced this pull request Nov 21, 2022
…ate OCMock (flutter#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
shogohida pushed a commit to shogohida/flutter that referenced this pull request Dec 7, 2022
…#115656)

* 19673b341 [camera]: Bump camerax_version (flutter/plugins#6709)

* b8282424e [gh_actions]: Bump ossf/scorecard-action from 2.0.4 to 2.0.6 (flutter/plugins#6610)

* 2ba4c0a70 [file_selector] Add getDirectoryPaths method to the file_selector_platform_interface. (flutter/plugins#6572)

* 89cbf74c8 [quick_actions]Migrates all remaining components to Swift, and deprecate OCMock (flutter/plugins#6597)

* 51d084453 [quick_actions] Fix Android integration test flake (flutter/plugins#6688)

* b2fe01bc0 [google_sign_in] Correctly passes `serverClientId` to native libs (flutter/plugins#6691)
gspencergoog pushed a commit to gspencergoog/flutter that referenced this pull request Jan 19, 2023
…#115656)

* 19673b341 [camera]: Bump camerax_version (flutter/plugins#6709)

* b8282424e [gh_actions]: Bump ossf/scorecard-action from 2.0.4 to 2.0.6 (flutter/plugins#6610)

* 2ba4c0a70 [file_selector] Add getDirectoryPaths method to the file_selector_platform_interface. (flutter/plugins#6572)

* 89cbf74c8 [quick_actions]Migrates all remaining components to Swift, and deprecate OCMock (flutter/plugins#6597)

* 51d084453 [quick_actions] Fix Android integration test flake (flutter/plugins#6688)

* b2fe01bc0 [google_sign_in] Correctly passes `serverClientId` to native libs (flutter/plugins#6691)
mauricioluz pushed a commit to mauricioluz/plugins that referenced this pull request Jan 26, 2023
…ate OCMock (flutter#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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App p: quick_actions platform-ios
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants