Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise iOS add-to-app usage page #3309

Merged

Conversation

xster
Copy link
Member

@xster xster commented Nov 27, 2019

@googlebot googlebot added the cla: yes Contributor has signed the Contributor License Agreement label Nov 27, 2019
demonstrate creating a `FlutterEngine`, exposed as a property, on app startup in
the app delegate.

<ul class="nav nav-tabs" id="engine-language" role="tablist">
Copy link
Member Author

Choose a reason for hiding this comment

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

@matthew-carroll see staging at https://add-to-app-2019.firebaseapp.com/docs/development/add-to-app/ios/add-flutter-screen.

This seems like a reasonable way of toggling languages for instructions in a way consistent with the aesthetics of the rest of the website.

It's generally recommended pre-warm a long-lived `FlutterEngine` for your
application. This way,

- Flutter screens will render their first frames faster.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Flutter will start the work to get to its first frame earlier.

Not sure how much the precision matters here, but having no VC doesn't actually speed up frame time.

Copy link
Member Author

Choose a reason for hiding this comment

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

VC doesn't actually speed up frame time

Not sure I understood the comment about having no VCs. I rephrased it a little bit nevertheless.

application. This way,

- Flutter screens will render their first frames faster.
- Your Flutter and Dart state could outlive one `FlutterViewController`.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm always a bit thrown by what Flutter means in this context. Do we just mean Flutter-specific application state?

Copy link
Member

Choose a reason for hiding this comment

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

"could" or "will"?

Copy link
Member Author

Choose a reason for hiding this comment

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

@dnfield I'm actually just kinda thinking anything you can conceptually assign to the term 'Flutter' and that has a state. Can you think of counter examples?

Replaced could with will

Copy link
Contributor

Choose a reason for hiding this comment

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

Is Flutter here the Flutter framework? The Flutter engine excluding the embedding? The embedding? Plugin code (dart/platform)?

Copy link
Member Author

@xster xster Nov 28, 2019

Choose a reason for hiding this comment

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

Doesn't the sentence apply the same way for all those definitions?

Tangent: I don't think the word embedding means anything for people outside the team and I'm tempted to keep it so for as long as we can since the distinction isn't necessarily useful unless you're trying to contribute to the engine code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess a way of looking at this is: here you use Flutter in a way that excludesFlutterViewController. Later in the document you're using Flutter in a way that explicitly means showing the FlutterViewController.

Copy link
Member Author

Choose a reason for hiding this comment

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

Isn't it a bit like having the sentences:

  • Having a backup of your movie will make it outlive one VHS tape
  • 'showMovie'

and then asking whether readers will be struggling understanding whether 'movie' here encompasses the mylar tape ribbons or not :)

It's likely immaterial whether they assume one way or another.

self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
// Runs the default Dart entrypoint with a default Flutter route.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should avoid mentioning the default Flutter route here. If anything, we should outline how to use platform channels to communicate with the Dart side to set up any non-default state.

Copy link
Member Author

Choose a reason for hiding this comment

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

We do have a default flutter route on the flutter side https://api.flutter.dev/flutter/widgets/Navigator/defaultRouteName-constant.html

Copy link
Contributor

Choose a reason for hiding this comment

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

It exists but it causes much confusion and frequently doesn't work as expected

Copy link
Member Author

Choose a reason for hiding this comment

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

Which part specifically are you commenting on?

The fact that there's a cascade going on in https://api.flutter.dev/flutter/material/MaterialApp-class.html and the top level navigator behavior? It's indeed confusing but it's just how Flutter works at the moment. I don't think it should ever not work as expected. This is a mostly orthogonal concept to the timing of calls to setInitialRoute.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's confusing becuase you can only set it at one point in the lifecycle of starting the engine, and you lose access to that completely if you set it up in certain ways, and if you call it too late it just silently fails, and there's no good way to fix any of those problems with the API so if you open a bug about it you'll be told you should be doing it differently anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ya, the mechanism for changing the default route is confusing as mentioned below. But it doesn't change the fact that there is a default route when you don't change it.

override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil);
self.flutterEngine?.run(withEntrypoint: nil);
// Runs the default Dart entrypoint with a default Flutter route.
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

- (void)viewDidLoad {
[super viewDidLoad];

// Make a button to call the showFlutter function below when pressed.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe showFlutterViewController?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think it adds much. Which misunderstanding are you trying to avoid for the reader?

Copy link
Contributor

Choose a reason for hiding this comment

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

what Flutter is.

Copy link
Member Author

Choose a reason for hiding this comment

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

Which user-self-assigned definition of the term Flutter would be problematic?


// Make a button to call the showFlutter function below when pressed.
let button = UIButton(type:UIButton.ButtonType.custom)
button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 222 to 223
sometimes useful if the Flutter screen is rarely shown and there are no good
heuristics to determine when the Dart VM should be started.
Copy link
Contributor

Choose a reason for hiding this comment

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

if the Flutter screen is rarely shown and does not need to persist state between apperances?

Copy link
Member Author

Choose a reason for hiding this comment

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

added into an enumeration

- Forwarding status bar taps (which can only be detected in the AppDelegate) to
Flutter for scroll-to-top behavior.

If your app delegate cannot directly subclass `FlutterAppDelegate`, you can
Copy link
Contributor

Choose a reason for hiding this comment

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

s/can/must right?

Copy link
Member Author

Choose a reason for hiding this comment

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

changed to should. Must is a bit strong since it's not like the app won't run anymore without it. We can point out the reasoning and let them decide.


## Building and running your app
An initial route can be set for your Flutter [`WidgetsApp`]({{site.api}}/flutter/widgets/WidgetsApp-class.html)
when constructing the engine.
Copy link
Contributor

Choose a reason for hiding this comment

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

If you choose to do this, you _must_ do so before running the engine, and any calls after running the engine will be ignored.

IMO, we should avoid documenting this API, deprecate it, and remove it. It's the source of a lot of confusion and it has no clear fix.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a warning box.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually there is already a warning box.

Comment on lines 531 to 534
In order to change your Flutter route after the `FlutterEngine` is already
running, use [pushRoute]({{site.api}}/objcdoc/Classes/FlutterViewController.html#/c:objc(cs)FlutterViewController(im)pushRoute:)
or [popRoute]({{site.api}}/objcdoc/Classes/FlutterViewController.html#/c:objc(cs)FlutterViewController(im)popRoute)
on the `FlutterViewController`.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is markedly different from setting an initial route, since it mutates the route stack, whereas setInitialRoute initializes the route stack to a specific spot.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wasn't suggesting that they are equivalent. It's in a tangential tip box.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a few more words to clarify difference.

Comment on lines +543 to +546
The above only illustrates a few examples of ways to customize how a Flutter
instance is initiated. Using [platform channels](/docs/development/platform-integration/platform-channels),
you're free to push data or prepare your Flutter environment in any way you'd
like before presenting the Flutter UI via a `FlutterViewController`.
Copy link
Contributor

Choose a reason for hiding this comment

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

IME, the routing logic for add-to-app is pretty limited and does unexpected things. I think it would be better to document how to use platform channels in this way here, and then we could mention that you can use any of the framework-provided channels as well (such as the navigation channel).

In other words, I think a user is far more likely to want to tell the running Dart program what state it should initialize to before presenting, and that it's very unlikely that the right way to do that will be setting an initial route (that only works at a specific point in execution) or pushing/popping routes blindly from the background.

Copy link
Contributor

Choose a reason for hiding this comment

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

Document platform channels in this way here -> document how to use a custom platform channel to communicate with Dart

Copy link
Member Author

Choose a reason for hiding this comment

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

I generally agree with you and using a custom channel to push an application specific DI-like bundle is what I would do too.

Though on the flip side, there's a bit of a personal taste involved in the trade off in the sense that writing platform channels is extremely boring and tedious (and error-prone in its own right as well) currently until we do flutter/flutter#32930.

Routes is also a non-trivially important concept in Flutter and we're not necessarily going to be avoiding pains for developers if we avoided this whole topic in documentations.

TL;DR, I think all present solutions have annoyances and we should properly handle this very common initialization use case and present a proper best practice with infrastructure in the coming phases, but we should have some docs in the meantime.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a bit more caveating for more transparency in the docs in the meantime.

Copy link
Member Author

Choose a reason for hiding this comment

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

oh look there's flutter/flutter#34170 already

Copy link
Contributor

Choose a reason for hiding this comment

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

SG. I can understand including this - my comment above sketches out a bit more of why (I think users will read this, get it wrong, think it's a bug, and be frustrated when we tell them it's by design). But maybe that's what we have right now.

Copy link
Member Author

Choose a reason for hiding this comment

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

ya, I hear you. There are tons of bugs around this already and I don't think routes are generally useful APIs, but I don't think we can move the weight of the community right now and we might get more confusion if the code is in the repo but we avoided talking about it.

Copy link
Contributor

@sfshaza2 sfshaza2 left a comment

Choose a reason for hiding this comment

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

Won't merge yet but LGTM.


```objective-c
{{site.alert.tip}}
It's generally recommended pre-warm a long-lived `FlutterEngine` for your
Copy link
Member

Choose a reason for hiding this comment

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

missing "to": "recommended to pre-warm"

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks!

application. This way,

- Flutter screens will render their first frames faster.
- Your Flutter and Dart state could outlive one `FlutterViewController`.
Copy link
Member

Choose a reason for hiding this comment

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

"could" or "will"?


- Flutter screens will render their first frames faster.
- Your Flutter and Dart state could outlive one `FlutterViewController`.
- You and your plugins can interact with Flutter and your Dart logic before
Copy link
Member

Choose a reason for hiding this comment

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

"Your application and plugins"?

Copy link
Member Author

Choose a reason for hiding this comment

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

sg, changed


#import "AppDelegate.h"

@implementation AppDelegate

// This override can be omitted if you do not have any Flutter Plugins.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Copy link
Member

Choose a reason for hiding this comment

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

I know you didn't edit this, but it should be NSDictionary<UIApplicationLaunchOptionsKey, id> *)

Copy link
Member Author

Choose a reason for hiding this comment

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

ah thanks

var flutterEngine : FlutterEngine?;
// Only if you have Flutter plugins.
class AppDelegate: FlutterAppDelegate { // More on the FlutterAppDelegate below.
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
Copy link
Member

Choose a reason for hiding this comment

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

Do we have engine naming conventions?

Copy link
Member Author

Choose a reason for hiding this comment

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

looking into it a bit, this only adds a debug label for the thread in instruments. I want to get rid of it so I'll not over-emphasize it here for now

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(showFlutter)
forControlEvents:UIControlEventTouchUpInside];
Copy link
Member

Choose a reason for hiding this comment

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

I think this is missing a few tabs in the front.

Copy link
Member Author

Choose a reason for hiding this comment

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

this is just lining up the semi-columns. Did I understand correctly?

action:@selector(showFlutter)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blueColor]];
Copy link
Member

Choose a reason for hiding this comment

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

I would love to start "modernizing" (~2012) at least our sample code with dot notation.

button.backgroundColor = UIColor.blueColor;

Copy link
Member Author

Choose a reason for hiding this comment

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

square brackets forever!


- (void)showFlutter {
FlutterEngine *flutterEngine =
[(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
Copy link
Member

Choose a reason for hiding this comment

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

UIApplication.sharedApplication.delegate.flutterEngine

Copy link
Member Author

Choose a reason for hiding this comment

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

<I didn't try it yet> don't we need to keep the cast to AppDelegate? </>

Copy link
Member

Choose a reason for hiding this comment

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

Oh yeah ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine

Copy link
Member Author

Choose a reason for hiding this comment

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

done

<div class="tab-pane active" id="vc-objc-tab" role="tabpanel" aria-labelledby="vc-objc-tab" markdown="1">

<?code-excerpt "ViewController.m" title?>
```objectivec
Copy link
Member

Choose a reason for hiding this comment

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

I thought the markdown language marker was objective-c?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure which syntax highlighter library we're using for the website. objective-c and objc don't work.

```

- Swift:
or
Copy link
Member

Choose a reason for hiding this comment

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

Should the two languages be in tabs?

Copy link
Member Author

Choose a reason for hiding this comment

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

lol you caught me. I got tired of writing all that html boilerplate

@@ -346,7 +622,7 @@ Connected views:

Attach to specific isolates instead in two steps:

1. Name the Flutter root isolate of interest in its Dart source.
1- Name the Flutter root isolate of interest in its Dart source.
Copy link
Member

Choose a reason for hiding this comment

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

Is 1- the normal markdown way to number steps on the website?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not, but the code highlighter makes the markdown parser crap out (it would have the wrong indent with the code block anyway)

@@ -358,7 +637,7 @@ void main() {
}
```

2. Run `flutter attach` with the `--isolate-filter` option.
2- Run `flutter attach` with the `--isolate-filter` option.

```bash
Copy link
Member

Choose a reason for hiding this comment

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

I think this is supposed to be ```terminal

Copy link
Member Author

Choose a reason for hiding this comment

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

oh nice, it looks way nicer, thanks


- (void)showFlutter {
FlutterEngine *flutterEngine =
[(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
Copy link
Member

Choose a reason for hiding this comment

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

Oh yeah ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine

@xster xster merged commit 8768f66 into flutter:staging-add-to-app-do-not-delete-until-2020 Nov 28, 2019
@xster xster deleted the ios-usage branch November 28, 2019 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Contributor has signed the Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants