Skip to content

Conversation

@tauu
Copy link
Contributor

@tauu tauu commented Feb 20, 2020

Description

A watchOS companion app can be added to a flutter app as described in the official documentation. But after doing flutter build and flutter run will no longer work. The root cause of this is that flutter will always pass either '-sdk iphoneos' or '-sdk iphonesimulator' to xcodebuild for iOS builds. Neither of these may be used to build an app with a watchOS companion app. (see e.g. Stackoverflow )

The changes in this pull request adjust the build settings if a watchOS companion app is detected in an iOS project and fix both flutter run and flutter build commands for iOS projects with a watchOS companion app.

Related Issues

This might be relevant for #28901.

Tests

I added the following tests:

  • none

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I signed the [CLA].
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read [Handling breaking changes].

  • No, no existing tests failed, so this is not a breaking change.

@fluttergithubbot fluttergithubbot added the tool Affects the "flutter" command-line tool. See also t: labels. label Feb 20, 2020
@fluttergithubbot
Copy link
Contributor

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment @googlebot I fixed it.. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ Googlers: Go here for more info.

@tauu
Copy link
Contributor Author

tauu commented Feb 20, 2020

@googlebot I fixed it.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@jonahwilliams
Copy link
Contributor

FYI @jmagman

@jmagman
Copy link
Member

jmagman commented Feb 20, 2020

#43731 (comment)

  1. SUPPORTED_PLATFORMS= iphoneos for Profile and Relase should be set in the Runner target, not the Runner project.
  2. -sdk iphoneos or -sdk iphonesimulator are set on every flutter build command: Support multi-arch iOS binaries #17312. I believe this should already be handled by the SDKROOT build setting, but I would need to test this.

@tauu
Copy link
Contributor Author

tauu commented Feb 20, 2020

Regarding 2. :
The -sdk parameter seems to be set independent of the SDKROOT build setting in

if (buildForDevice) {
buildCommands.addAll(<String>['-sdk', 'iphoneos']);
} else {
buildCommands.addAll(<String>['-sdk', 'iphonesimulator', '-arch', 'x86_64']);
}

I tried using the SDKROOT setting, but couldn't get rid of the -sdk parameter this way.

In addition just dropping the -sdk parameter is unfortunately not sufficient for simulator builds. For these also -destination id=<deviceid> with a valid simulator device identifier (or alternatively a valid iphone model name) has to be set. This is also automatically handled by the changes in this pull request.

@codecov
Copy link

codecov bot commented Feb 20, 2020

Codecov Report

Merging #51126 into master will decrease coverage by 3.94%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #51126      +/-   ##
==========================================
- Coverage   69.52%   65.58%   -3.95%     
==========================================
  Files         204      208       +4     
  Lines       22737    22201     -536     
==========================================
- Hits        15809    14560    -1249     
- Misses       6928     7641     +713     
Flag Coverage Δ
#flutter_tool 65.58% <0.00%> (-3.95%) ⬇️
Impacted Files Coverage Δ
packages/flutter_tools/lib/src/aot.dart 0.00% <0.00%> (-65.68%) ⬇️
...tter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart 0.00% <0.00%> (-53.34%) ⬇️
...lutter_tools/lib/src/commands/update_packages.dart 1.52% <0.00%> (-26.71%) ⬇️
...s/flutter_tools/lib/src/persistent_tool_state.dart 69.56% <0.00%> (-23.03%) ⬇️
packages/flutter_tools/lib/src/base/build.dart 80.46% <0.00%> (-12.74%) ⬇️
packages/flutter_tools/lib/src/ios/simulators.dart 53.64% <0.00%> (-12.33%) ⬇️
...ages/flutter_tools/lib/src/linux/linux_device.dart 71.42% <0.00%> (-11.19%) ⬇️
packages/flutter_tools/lib/src/web/workflow.dart 88.88% <0.00%> (-11.12%) ⬇️
...es/flutter_tools/lib/src/linux/linux_workflow.dart 88.88% <0.00%> (-11.12%) ⬇️
...s/flutter_tools/lib/src/macos/xcode_validator.dart 85.71% <0.00%> (-9.53%) ⬇️
... and 164 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 846e8fe...c73bb88. Read the comment docs.

@jmagman
Copy link
Member

jmagman commented Feb 24, 2020

Regarding 2. :
The -sdk parameter seems to be set independent of the SDKROOT build setting in

if (buildForDevice) {
buildCommands.addAll(<String>['-sdk', 'iphoneos']);
} else {
buildCommands.addAll(<String>['-sdk', 'iphonesimulator', '-arch', 'x86_64']);
}

I tried using the SDKROOT setting, but couldn't get rid of the -sdk parameter this way.
In addition just dropping the -sdk parameter is unfortunately not sufficient for simulator builds. For these also -destination id=<deviceid> with a valid simulator device identifier (or alternatively a valid iphone model name) has to be set. This is also automatically handled by the changes in this pull request.

Sorry for being unclear, I meant could we get rid of -sdk in favor of SDKROOT? But I just tested it and it causes the same compilation error:

error: unable to resolve product type 'com.apple.product-type.watchkit2-extension' for platform 'iphonesimulator' (in target 'TestClock Extension' from project 'Runner')
error: unable to resolve product type 'com.apple.product-type.watchkit2-extension' for platform 'iphonesimulator' (in target 'TestClock Extension' from project 'Runner')

Requiring a destination for apps with companions seems like a good compromise, so thanks for this solution!

A few concerns:

  1. This needs tests. Unfortunately there are zero unit tests for any Xcode build code paths that I can find, and writing the first one is a big ask, considering the process and file system mocking requirements (we have some technical debt to pay down there).

An "easier" way to test this may be to add a new ~/Projects/flutter/dev/integration_tests/ios_app_with_watch_companion project that contains a companion app, and confirm it does not build before your change, and does build after.
Then add a new dev/devicelab/bin/tasks/app_with_watch_companion.dart integration test to run on post-submit that does something like:

      final Directory watchApp = Directory(path.join(tempDir.path, 'app_with_watch'));
      mkdir(watchApp);
      recursiveCopy(
        Directory(path.join(flutterDirectory.path, 'dev', 'integration_tests', 'ios_app_with_watch_companion')),
        watchApp,
      );

final Directory objectiveCHostApp = Directory(path.join(tempDir.path, 'hello_host_app'));
for something similar.
The rub here is that your change requires a real destination. So you'd have to add simctl code to your dart test as setup (this needs to be exec'd in dart, but I just tested this in bash as an example)

$ xcrun simctl create "TestFlutterWatch" "Apple Watch Series 5 - 44mm" 
709E9D7C-5D9D-4753-8423-F3BB7515E6FB
$ xcrun simctl create "TestFlutteriPhoneWithWatch" "iPhone 11"
375D81C8-0EB4-4CFF-A14F-1066C9B85EED
$ xcrun simctl pair 709E9D7C-5D9D-4753-8423-F3BB7515E6FB 375D81C8-0EB4-4CFF-A14F-1066C9B85EED
2360C20E-86EC-454C-8BF2-9053AD6AAE93
      await inDirectory(watchApp, () async {
        await flutter(
          'build',
          options: <String>[
         'ios',
          '--no-codesign',
          '-d',
          '2360C20E-86EC-454C-8BF2-9053AD6AAE93',
          ],
        );
      });

Then needs to be cleaned up in a finally:

$ xcrun simctl delete 375D81C8-0EB4-4CFF-A14F-1066C9B85EED
$ xcrun simctl delete 709E9D7C-5D9D-4753-8423-F3BB7515E6FB

To be tested like:

$ cd dev/devicelab
$ dart bin/run.dart -t app_with_watch_companion

Then added to

if (Platform.isMacOS) () => _runDevicelabTest('plugin_lint_mac'),

if (Platform.isMacOS) () => _runDevicelabTest('app_with_watch_companion'),

(And you can see why I haven't gotten around to fixing this yet 😄).

For some reason this leads to TARGET_BUILD_DIR always ending in 'iphoneos' even though the actual directory will end with 'iphonesimulator' for simulator builds.

This is very concerning, and I saw this in my own tests, too I'm not sure what other issues this will cause.

Copy link
Member

Choose a reason for hiding this comment

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

Don't set a default, we need to handle null being passed in, anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, default has been removed

Copy link
Member

Choose a reason for hiding this comment

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

  1. Remove space between ! and buildForDevice.
  2. Handle null deviceID

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines +213 to +235
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the good comments!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're welcome. :-)

Choose a reason for hiding this comment

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

Ended up here looking for reasons why xcodebuild was throwing errors. Turn's out this comment was the key! Do you happen to have any resources describing why -sdk causes issues with projects with WatchKit dependencies?

In the end, bloody amazing comment!

Copy link
Member

Choose a reason for hiding this comment

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

"build a flutter a flutter app" -> "build an app with a companion watch"
Can you mention that the ID should be passed in with the --devices flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

Remove space

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

Remove space

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

You need to check that this file actually exists. INFOPLIST_FILE can be moved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, a check has been added.

@jmagman
Copy link
Member

jmagman commented Feb 24, 2020

Oh, another thing:
As I mentioned in #43731 (comment), I believe this change will also require setting SUPPORTED_PLATFORMS= iphoneos for Profile and Release in the Runner target, and NOT the Runner project for new projects. When the companion app is added, it inherits those settings from the Runner project, which isn't correct. We can address that in another change.

@solid-yuriiprykhodko
Copy link

Hi!
I've tested the fix on the Simulator, works great, thanks!

However, I've tried using it to run the Flutter app on a physical device, and that failed:

Yuriis-MacBook-Pro:ios yuriiprykhodko$ flutter run -d ***
Changing current working directory to: /Users/yuriiprykhodko/IdeaProjects/-/packages/--
Launching lib/main.dart on iPhone in debug mode...
 

Automatically signing iOS for device deployment using specified development team in Xcode project: -
Watch companion app found. Adjusting build settings.
Running Xcode build...                                                  
                                                   
Xcode build done.                                            7.6s
Failed to build iOS app
Error output from Xcode build:
↳
    2020-02-25 22:22:10.629 xcodebuild[44321:3660406]  DTDeviceKit: deviceType from - was NULL
    ** BUILD FAILED **


Xcode's output:
↳
    While building module 'Flutter' imported from /Users/yuriiprykhodko/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/ios/Classes/FLTPathProviderPlugin.h:5:
    In file included from <module-includes>:1:
    In file included from /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/Flutter.h:54:
    In file included from /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterAppDelegate.h:11:
    /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterPlugin.h:314:11: warning: parameter 'gestureBlockingPolicy' not found in the
    function declaration [-Wdocumentation]
     * @param gestureBlockingPolicy How UIGestureRecognizers on the platform views are
              ^~~~~~~~~~~~~~~~~~~~~
    /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterPlugin.h:314:11: note: did you mean 'gestureRecognizersBlockingPolicy'?
     * @param gestureBlockingPolicy How UIGestureRecognizers on the platform views are
              ^~~~~~~~~~~~~~~~~~~~~
              gestureRecognizersBlockingPolicy
    1 warning generated.
    1 warning generated.
    While building module 'Flutter' imported from /Users/yuriiprykhodko/.pub-cache/hosted/pub.dartlang.org/flutter_mailer-0.4.2/ios/Classes/FlutterMailerPlugin.h:1:
    In file included from <module-includes>:1:
    In file included from /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/Flutter.h:54:
    In file included from /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterAppDelegate.h:11:
    /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterPlugin.h:314:11: warning: parameter 'gestureBlockingPolicy' not found in the
    function declaration [-Wdocumentation]
     * @param gestureBlockingPolicy How UIGestureRecognizers on the platform views are
              ^~~~~~~~~~~~~~~~~~~~~
    /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Flutter/Flutter.framework/Headers/FlutterPlugin.h:314:11: note: did you mean 'gestureRecognizersBlockingPolicy'?
     * @param gestureBlockingPolicy How UIGestureRecognizers on the platform views are
              ^~~~~~~~~~~~~~~~~~~~~
              gestureRecognizersBlockingPolicy
    1 warning generated.
    1 warning generated.
    Command CompileSwift failed with a nonzero exit code
    mkdir -p /Users/yuriiprykhodko/IdeaProjects/-/packages/--/build/ios/Debug-watchos/Watch Extension.appex/Frameworks
    rsync --delete -av --filter P .*.?????? --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules"
    "/Users/yuriiprykhodko/IdeaProjects/-/packages/--/build/ios/Debug-watchos/AppleWatchInfoService/AppleWatchInfoService.framework"
    "/Users/yuriiprykhodko/IdeaProjects/-/packages/--/build/ios/Debug-watchos/Watch Extension.appex/Frameworks"
    building file list ... done
    AppleWatchInfoService.framework/
    AppleWatchInfoService.framework/Info.plist

    sent 980 bytes  received 48 bytes  2056.00 bytes/sec
    total size is 297691  speedup is 289.58
    /Users/yuriiprykhodko/IdeaProjects/-/packages/--/ios/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh: line 141: ARCHS[@]: unbound variable
    Command PhaseScriptExecution failed with a nonzero exit code
    note: Using new build system
    note: Planning build
    note: Constructing build description
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'Zip' from project 'Pods')
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'Watch Extension' from project 'Runner')
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'Starscream' from project 'Pods')
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'Pods-Watch Extension' from project 'Pods')
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'LogServer' from project 'Pods')
    warning: None of the architectures in ARCHS (arm64) are valid. Consider setting ARCHS to $(ARCHS_STANDARD) or updating it to include at least one value from VALID_ARCHS (arm64_32, armv7k). (in target 'AppleWatchInfoService' from project 'Pods')

Could not build the precompiled application for the device.

Error launching application on iPhone.

Flutter doctor output and version:

Yuriis-MacBook-Pro:ios yuriiprykhodko$ flutter doctor -v
[✓] Flutter (Channel apple-watch, v1.10.2-pre.2052, on Mac OS X 10.15.3 19D76, locale en-GB)
    • Flutter version 1.10.2-pre.2052 at /Users/yuriiprykhodko/dev/flutter2
    • Framework revision cf20a295f1 (5 days ago), 2020-02-20 17:51:42 +0100
    • Engine revision f2f8c342be
    • Dart version 2.8.0 (build 2.8.0-dev.9.0 0f141be8bd)

 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/yuriiprykhodko/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.3.1, Build version 11C504
    • CocoaPods version 1.8.4

[!] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] IntelliJ IDEA Ultimate Edition (version 2019.3.2)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 42.1.4
    • Dart plugin version 193.6015.53

[✓] VS Code (version 1.42.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.7.1

[✓] Connected device (1 available)
    • iPhone • *** • ios • iOS 13.3.1

! Doctor found issues in 1 category.

Yuriis-MacBook-Pro:ios yuriiprykhodko$ flutter --version
Flutter 1.10.2-pre.2052 • channel apple-watch • https://github.com/tauu/flutter.git
Framework • revision cf20a295f1 (5 days ago) • 2020-02-20 17:51:42 +0100
Engine • revision f2f8c342be
Tools • Dart 2.8.0 (build 2.8.0-dev.9.0 0f141be8bd)

Perhaps we could address this in some further issue?

And given that we need to implement and test some interaction between the apps, another problem appears.
We will have to manually grab the WatchKit extension from build/ios/Debug-iphonesimulator/<iOS app name>.app/Watch/<watchOS Extension name>.app, and install it on a paired Watch Simulator to work on the applications.
We could do that via xcrun simclt install <Watch Sim UDID> <dir to Watchkit extension> and xcrun simctl launch <Watch Sim UDID> <app bundleId>
Possibly we could add that to the flutter_tool as well?

@Henrik-glt
Copy link

@tauu Any plan on following up the change request from @jmagman ? 🙂

@tauu
Copy link
Contributor Author

tauu commented Mar 23, 2020

@Henrik-glt yes, of course! I plan to implement it this / next week :-) Sorry for the delay, but recent world wide events kinda forced me to work on more immediate projects. :-(

@Henrik-glt
Copy link

@Henrik-glt yes, of course! I plan to implement it this / next week :-) Sorry for the delay, but recent world wide events kinda forced me to work on more immediate projects. :-(

Great! Looking forward to getting this important fix to master. 😃 Great work mate, completely understand that people need to prioritise during this weird time.

@zanderso zanderso added work in progress; do not review waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds and removed work in progress; do not review labels Mar 26, 2020
@john-yick

This comment has been minimized.

@tauu
Copy link
Contributor Author

tauu commented Apr 10, 2020

@jmagman Sorry that it took so long - hope the overall situation gets less stressful soon.
Thanks for the detailed instructions on how to create devicelab tests! That was very helpful. The latest commits adds a sample app with an watch companion and tests for

  • Building the sample app for a device in release / debug mode.
  • Building the sample app in debug mode for a simulated device.
  • Running the sample app on a simulated device.

Build for a simulated device seems to use a different codepath than running on a simulated device, as buildForDevice will be true in buildXcodeProject(...) for the first one but not for the second one.

As I mentioned in #43731 (comment), I believe this change will also require setting SUPPORTED_PLATFORMS= iphoneos for Profile and Release in the Runner target, and NOT the Runner project for new projects. When the companion app is added, it inherits those settings from the Runner project, which isn't correct. We can address that in another change.

That is definately a good idea. Can confirm that in my test, the companion app inherited the iphoneos setting from the Runner project. Moving the setting to the Runner target fixes the issue.

One more thing: As running the devicelab tests with other locales than en_US fails (likely en_* also works, not tested), would it be possible to add the following text to https://github.com/flutter/flutter/wiki/Running-and-writing-tests in the section "Running device lab tests locally" between items 2. and 3.:

  1. Ensure that the current locale is en_US. Setting the locale of a terminal can be achieved by executing the command export LANG=en_US.UTF-8.

@jmagman
Copy link
Member

jmagman commented Apr 10, 2020

@tauu Thank you so much for working on this, I can tell you put in a lot of time and thought! I'll look at it in detail today!

One more thing: As running the devicelab tests with other locales than en_US fails (likely en_* also works, not tested), would it be possible to add the following text to https://github.com/flutter/flutter/wiki/Running-and-writing-tests in the section "Running device lab tests locally" between items 2. and 3.:

  1. Ensure that the current locale is en_US. Setting the locale of a terminal can be achieved by executing the command export LANG=en_US.UTF-8.

Great idea, done. Also created an issue for the tests to do this for you.

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.

  1. You can delete dev/integration_tests/ios_app_with_watch_companion/android/ and dev/integration_tests/ios_app_with_watch_companion/web/ and dev/integration_tests/ios_app_with_watch_companion/test since they aren't needed for the test. That will also make the dev/integration_tests/ios_app_with_watch_companion/android/app/src/main/res/values/styles.xml:13: trailing U+0020 space character analyzer issue go away.
  2. I checked out this change and it cleanly rebases onto top of tree master, but unfortunately it doesn't build on top of #51444:
packages/flutter_tools/lib/src/project.dart:482:48: Error: Getter not found: 'instance'.
      if (infoFile.existsSync() && PlistParser.instance.getValueFromFile(infoFile.path, 'WKCompanionAppBundleIdentifier') == bundleIdentifier) {

You can replace PlistParser.instance with globals.plistParser (we're migrating to be explicit about "global" state so we can start removing it to inject dependencies more explicitly, see #47161)

I'm also hitting a linker error when I flutter build ios in the new integration test directory. I'll investigate that more on Monday.

Thank you so much for this, it's awesome!

Comment on lines 13 to 14
Copy link
Member

Choose a reason for hiding this comment

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

You can leave off instantiating these and check if they are null in the finally.

String watchDeviceID;
String phoneDeviceID;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, that sounds better, done.

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 you're missing a brace here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed I missed a brace, fixed.

Copy link
Member

Choose a reason for hiding this comment

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

I took the liberty of writing some unit tests for this since I know this file is really gross to test. You can put them in project_test.dart or I'd be happy to push it to your fork, if you prefer.

    group('watch companion', () {
      MemoryFileSystem fs;
      MockPlistUtils mockPlistUtils;
      MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
      FlutterProjectFactory flutterProjectFactory;
      setUp(() {
        fs = MemoryFileSystem.test();
        mockPlistUtils = MockPlistUtils();
        mockXcodeProjectInterpreter = MockXcodeProjectInterpreter();
        flutterProjectFactory = FlutterProjectFactory();
      });

      testUsingContext('cannot find bundle identifier', () async {
        final FlutterProject project = await someProject();
        expect(await project.ios.containsWatchCompanion(<String>['WatchTarget']), isFalse);
      }, overrides: <Type, Generator>{
        FileSystem: () => fs,
        ProcessManager: () => FakeProcessManager.any(),
        PlistParser: () => mockPlistUtils,
        XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
        FlutterProjectFactory: () => flutterProjectFactory,
      });

      group('with bundle identifier', () {
        setUp(() {
          when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenAnswer(
              (_) {
              return Future<Map<String,String>>.value(<String, String>{
                'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
              });
            }
          );
        });

        testUsingContext('no Info.plist in target', () async {
          final FlutterProject project = await someProject();
          expect(await project.ios.containsWatchCompanion(<String>['WatchTarget']), isFalse);
        }, overrides: <Type, Generator>{
          FileSystem: () => fs,
          ProcessManager: () => FakeProcessManager.any(),
          PlistParser: () => mockPlistUtils,
          XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
          FlutterProjectFactory: () => flutterProjectFactory,
        });

        testUsingContext('Info.plist in target does not contain WKCompanionAppBundleIdentifier', () async {
          final FlutterProject project = await someProject();
          project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);

          expect(await project.ios.containsWatchCompanion(<String>['WatchTarget']), isFalse);
        }, overrides: <Type, Generator>{
          FileSystem: () => fs,
          ProcessManager: () => FakeProcessManager.any(),
          PlistParser: () => mockPlistUtils,
          XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
          FlutterProjectFactory: () => flutterProjectFactory,
        });

        testUsingContext('target WKCompanionAppBundleIdentifier is not project bundle identifier', () async {
          final FlutterProject project = await someProject();
          project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);

          when(mockPlistUtils.getValueFromFile(any, 'WKCompanionAppBundleIdentifier')).thenReturn('io.flutter.someOTHERproject');
          expect(await project.ios.containsWatchCompanion(<String>['WatchTarget']), isFalse);
        }, overrides: <Type, Generator>{
          FileSystem: () => fs,
          ProcessManager: () => FakeProcessManager.any(),
          PlistParser: () => mockPlistUtils,
          XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
          FlutterProjectFactory: () => flutterProjectFactory,
        });

        testUsingContext('has watch companion', () async {
          final FlutterProject project = await someProject();
          project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
          when(mockPlistUtils.getValueFromFile(any, 'WKCompanionAppBundleIdentifier')).thenReturn('io.flutter.someProject');

          expect(await project.ios.containsWatchCompanion(<String>['WatchTarget']), isTrue);
        }, overrides: <Type, Generator>{
          FileSystem: () => fs,
          ProcessManager: () => FakeProcessManager.any(),
          PlistParser: () => mockPlistUtils,
          XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
          FlutterProjectFactory: () => flutterProjectFactory,
        });
      });
    });

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks a lot! Totally agree that tests for containsWatchCompanion should be included (... and that writing tests for the plist file is not exactly fun ;-) )

Copy link
Member

Choose a reason for hiding this comment

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

(... and that writing tests for the plist file is not exactly fun ;-) )

Ugh I know, tell me about it. 😝
We're working on making tool tests easier to write, though mocking out a plist parser may never be anyone's favorite pastime.

Copy link
Member

Choose a reason for hiding this comment

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

If you rebase onto master and run flutter build ios in this directory, it should automatically migrate this project to fix #50568. See https://flutter.dev/docs/development/ios-project-migration also for details.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again thanks for the information, done.

@tauu
Copy link
Contributor Author

tauu commented Apr 15, 2020

Thanks for merging #54787 so fast! :-)

@jmagman jmagman removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Apr 15, 2020
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, thanks again for doing this!

@tauu
Copy link
Contributor Author

tauu commented Apr 15, 2020

No problem, always a pleasure submitting PRs to the flutter project. Thank you for all the detailed feedback.

@Henrik-glt
Copy link

Henrik-glt commented Apr 16, 2020

@tauu Are you able to run using flutter run when your iOS app has a watch extension?
I've tried to get my app with an Apple Watch extension to run, but no luck so far.

When I use legacy build system I get the following error:

Prepare build
               note: Using legacy build system
               === BUILD TARGET TestWatch Extension OF PROJECT Runner WITH CONFIGURATION Debug ===
           
               Check dependencies
               No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=arm64, VALID_ARCHS=arm64_32 armv7k).

This seems to be caused flutter specifying architecture arm64, but that is not a valid architecture for the watch extension.

When I use the "new" build system I get an error saying that signing doesn't match parent app.

Running flutter build ios works now however (great work! :) )

Am I missing something obvious?

Errors produced by switching to master (flutter channel master), run flutter upgrade and then flutter run

@tauu
Copy link
Contributor Author

tauu commented Apr 16, 2020

@Henrik-glt Can confirm that using flutter run to run a flutter app with a watch companion does not work for a real device. Just tried it and I get the same error message.

Embedded binary is not signed with the same certificate as the parent app.

Sorry apparently I missed checking it this way. Running the app on a real device from XCode works though. So likely the build process employed by flutter run differs in some way from what XCode does, will investigate it further.

@tauu
Copy link
Contributor Author

tauu commented Apr 16, 2020

@Henrik-glt: Found the issue and proposed a fix for it #54959.

@Henrik-glt
Copy link

@tauu Works like a charm! Great work and many thanks for fixing this!

@mgonzalezc
Copy link

Hello,

Does anybody have a workaround in case WKCompanionAppBundleIdentifier is not the app bundle itself but a build variable like ${APP_BUNDLE}?

We have different bundle identifiers in our app so we need to have it in this way.

@wph144
Copy link

wph144 commented Feb 24, 2022

Hello,

Does anybody have a workaround in case WKCompanionAppBundleIdentifier is not the app bundle itself but a build variable like ${APP_BUNDLE}?

We have different bundle identifiers in our app so we need to have it in this way.

I have same issue. I use flavor like com.foo.bar and com.foo.bar.dev
If I set WKCompanionAppBundleIdentifier = "com.foo.bar${BUNDLE_ID_SUFFIX}", build fails

@wph144
Copy link

wph144 commented Feb 24, 2022

Hello,
Does anybody have a workaround in case WKCompanionAppBundleIdentifier is not the app bundle itself but a build variable like ${APP_BUNDLE}?
We have different bundle identifiers in our app so we need to have it in this way.

I have same issue. I use flavor like com.foo.bar and com.foo.bar.dev If I set WKCompanionAppBundleIdentifier = "com.foo.bar${BUNDLE_ID_SUFFIX}", build fails

I reolved using hacky solution.

Despite of additional fix for substituting variable (Skogsfrae@584801d), I failed substituting "com.foo.bar${BUNDLE_ID_SUFFIX}"

However "$(PRODUCT_BUNDLE_IDENTIFIER)" success

So I added the following to ../Runner/Info.plist

    <key>WKCompanionAppBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>

$(PRODUCT_BUNDLE_IDENTIFIER) is what value I want (e.g., "com.foo.bar.dev", etc) only where in Runner target.

auto-submit bot pushed a commit that referenced this pull request Mar 5, 2024
…144607)

flutter/engine@d514a30...17a4b66

2024-03-05 [email protected] Roll Skia from a577399ed6fb to 5839a94bf28b (1 revision) (flutter/engine#51194)
2024-03-05 [email protected] [Impeller] Turn off StC. (flutter/engine#51191)
2024-03-05 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Reland: [macOS] Use CVDisplayLink to drive repaint (#51126)" (flutter/engine#51192)
2024-03-05 [email protected] Roll Skia from 9c62e7b382cf to a577399ed6fb (1 revision) (flutter/engine#51190)
2024-03-05 [email protected] Reland "Remove migration flag and unused header files #50216" (flutter/engine#50259)
2024-03-05 [email protected] Shift git version fetching to tools/gn (flutter/engine#51175)
2024-03-05 [email protected] [fuchsia] Remove now unnecessary diagnostics directory (flutter/engine#51180)
2024-03-05 [email protected] [Impeller] Enable depth buffer clipping & Stencil-then-Cover path rendering. (flutter/engine#50856)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.