かなり適当にMacBookにFlutterを入れて、最低動くようになったので、次はソースコード作成(の前に、昨日適当に入れたFlutter環境の復習)。よくできたIDEを使うのがまともなんだけど、エディタのKeyBindの関係で自分は素のTerminal(Emacs)派なので、、TestDriveの章では、Terminal & editor を選択、
docs.flutter.dev
ちなみに、、Emacsな人用のプラグイン?(ELプログラム?)もあるようであった。
https://docs.flutter.dev/get-started/editor?tab=emacs
どういう理屈か分からないが、以下のコマンドで、MAC上でSimulatorが起動できる
% pwd /Users/<user_name>/lang/flutter/my_app % open -a Simulator
この状態で再度flutterを実行すると、どの環境で走らせるのか?と聞いてくる
% flutter run [1]: iphone (46717xxxxxxxxxxxxxxxxxxxxx3434e) [2]: iPod touch (7th generation) (EF6548CA-291A-4848-8EA1-48BB692CC5A2) [3]: Chrome (chrome) Please choose one (To quit, press "q/Q"):
[1]を選ぶと自分のiPhoneにアプリが表示されるはずだが、signatureでエラーになった。(実機でテストするのは大事だが、すぐにロックするで面倒というのもあり)後で調べるとして、、先ほど走らせたSimulatorの[2]にしてみる。
MAC上のSimulatorでテストプログラムが走り出した。この時のコンソールのメッセージは以下
Launching lib/main.dart on iPod touch (7th generation) in debug mode... Running Xcode build... └─Compiling, linking and signing... 71.8s Xcode build done. 116.6s Syncing files to device iPod touch (7th generation)... 2,284ms Flutter run key commands. r Hot reload. 🔥🔥🔥 R Hot restart. h List all available interactive commands. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). 💪 Running with sound null safety 💪 An Observatory debugger and profiler on iPod touch (7th generation) is available at: http://127.0.0.1:49458/0h3Zk1RL3vg=/ The Flutter DevTools debugger and profiler on iPod touch (7th generation) is available at: http://127.0.0.1:9100?uri=http://127.0.0.1:49458/0h3Zk1RL3vg=/
rを押すと Hot reloadと言ってるので、ソースを修正して、r の押下でSimulatorの画面が変わるよということか。
試しに、my_app/lib/main.dartの文字列を編集して、先ほどのコンソールでr を押してみる。
コンソールには以下のメッセージが表示されて、Simulatorに修正された文字列が表示された。
Performing hot reload... Reloaded 1 of 583 libraries in 497ms.
デモ版のmain.dartに対して文字列を変えたところ。hot reloadでほとんど遅延なく更新が反映される
rを押すのが面倒だが、、まぁリビルドより格段に楽ではある。だいたい、やることが分かったので、、スクラッチから画面を作るレッスンに移りたい。Flutterで最初に起動されるのが、main.dartと思うがそれなりにややこしい。画面というかフレームの入れ子構造になっているのだろうという程度しから分からん。でも、フレームワークが全部把握できるのだとしたら、裏で何やってるのか分からないというフラストレーションは軽減される(公開されているソースが理解できるかどうかはおいといて)。
tutorialに倣っておらず順番はめちゃくちゃだが、今の環境で使えるデバイスは以下3種類、一つ目は自分の実機、残りはエミュレータやブラウザ
% flutter devices ipodune (mobile) • 46717xxxxxxxxxxxxxxxxxx34e • ios • iOS 15.1 19B74 iPod touch (7th generation) (mobile) • EF6548CA-291A-4848-8EA1-48BB692CC5A2 • ios • com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator) Chrome (web) • chrome • web-javascript • Google Chrome 97.0.4692.99
次にやるべきは、、サンプルから離れて、自力?でスマフォアプリのHelloWorldを出すと。。
docs.flutter.dev
プロジェクトをすべて手で書くのは到底無理なので、多分、flutter create
% flutter create testapp01 Signing iOS app for device deployment using developer identity: "Apple Development: <usr_name> (26xxxxxxxD)" Creating project testapp01... Running "flutter pub get" in testapp01... 3.6s Wrote 96 files. All done! In order to run your application, type: $ cd testapp01 $ flutter run Your application code is in testapp01/lib/main.dart.
tutorial通りなので書くほどでもないが、、以下のhello worldに書き換えて、flutter runでSimulator上でhello worldが表示される。
// Copyright 2018 The Flutter team. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Welcome to Flutter', home: Scaffold( appBar: AppBar( title: const Text('Welcome to Flutter'), ), body: const Center( child: Text('Hello World'), ), ), ); } }
(WindowsPCからVNCでMACの画面を表示)
自分の備忘録とご参考のためtutorialの解説を和訳して転記
- このサンプルは、マテリアルアプリである。Materialは、モバイルとWebで標準となっているビジュアルデザイン言語である。
- pubspec.yamlファイルのflutterセクションにuses-material-design: trueエントリを含めることを推奨。これにより、マテリアルのより多くの機能が使用可能となる
- MyAppクラスは上位のStatelessWidgetクラスから継承されており、アプリ自体がウィジェット。Flutterでは、配置、パディング、レイアウトなど、ほとんどすべてがウィジェット
- Scaffoldウィジェットは、デフォルトのアプリバーと、ホーム画面のウィジェットツリーを保持するbodyプロパティを提供する
- ウィジェットの主な仕事はbuild()メソッドを提供すること。build()では下位レベルのウィジェットの表示方法を規定する
- サンプルでは、子ウィジェットCenterを含むウィジェットで構成されている。TextCenterウィジェットは、ウィジェットサブツリーを画面の中央にそろえる
次のお題は、無限リストビューであった。ソースは以下
// Copyright 2018 The Flutter team. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:english_words/english_words.dart'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context){ return const MaterialApp( title: 'Startup Name Generator', home: RandomWords(), ); } } class _RandomWordsState extends State<RandomWords> { final _suggestions = <WordPair>[]; final _biggerFont = const TextStyle(fontSize: 18); Widget _buildSuggestions(){ return ListView.builder( padding: const EdgeInsets.all(16), itemBuilder: /*1*/ (context, i){ if (i.isOdd){ return const Divider(); /*2*/ } final index = 1 ~/2; /*3*/ if (index >= _suggestions.length){ _suggestions.addAll(generateWordPairs().take(10)); /*4*/ } return _buildRow(_suggestions[index]); }, ); } Widget _buildRow(WordPair pair){ return ListTile( title: Text( pair.asPascalCase, style: _biggerFont, ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Startup Name Generator'), ), body: _buildSuggestions(), ); } } class RandomWords extends StatefulWidget { const RandomWords({Key? key }):super(key:key); @override _RandomWordsState createState() => _RandomWordsState(); }
以下が、ソースの作成、ならびに、実行中の画面*1。
正しく動くとランダムに名前が出るはずだが、同じ名前が出ている。どこかにバグがある。が、、まだコード分かっていないのでデバッグできない。スキルが高まると、原因が分かるようになるだろう。そのうち、多分。
バグっているとはいえ、自分のiphoneでも動くように、releaseビルドをしている。。エラーになった。
% flutter run --release Multiple devices found: iphone (mobile) ? 4671xxxxxxxxxxxx4e ? ios ? iOS 15.1 19B74 iPod touch (7th generation) (mobile) ? EF6548CA-291A-4848-8EA1-48BB692CC5A2 ? ios ? com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator) Chrome (web) ? chrome ? web-javascript ? Google Chrome 97.0.4692.99 [1]: iphone (4671xxxxxxxxxxxxxxxxxxxxxxxx434e) [2]: iPod touch (7th generation) (EF6548CA-291A-4848-8EA1-48BB692CC5A2) [3]: Chrome (chrome) Please choose one (To quit, press "q/Q"): 1 Launching lib/main.dart on iphone in release mode... Automatically signing iOS for device deployment using specified development team in Xcode project: JWxxxxxxS9 Running Xcode build... Xcode build done. 14.1s Failed to build iOS app Error output from Xcode build: ? ** BUILD FAILED ** Xcode's output: ? Writing result bundle at path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.3csiU6/flutter_ios_build_temp_dirarTlAc/temporary_xcresult_bundle Failed to package /Users/<user_name>/lang/flutter/testapp01. Command PhaseScriptExecution failed with a nonzero exit code note: Using new build system note: Planning note: Build preparation complete note: Building targets in dependency order Result bundle written to path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.3csiU6/flutter_ios_build_temp_dirarTlAc/temporary_xcresult_bundle Could not build the precompiled application for the device. It appears that your application still contains the default signing identifier. Try replacing 'com.example' with your signing id in Xcode: open ios/Runner.xcworkspace Error running application on iphone.
signing idがおかしいと書かれているようだが、、署名が違ってるのか?
% pwd /Users/<user_name>/lang/flutter/testapp01/ios/Runner.xcodeproj % cat project.pbxproj | grep example PRODUCT_BUNDLE_IDENTIFIER = com.example.testapp01; PRODUCT_BUNDLE_IDENTIFIER = com.example.testapp01; PRODUCT_BUNDLE_IDENTIFIER = com.example.testapp01;
上記はexampleのままなので、、これは変える必要があるだろう。。
これは、もとのTutorialの、「Deploy to iOS devices」のセクションで、bundle IDをチェックしろよというのをすっ飛ばしているからだろう。。
appleのdeveloperサイトでAppIDを新たに取って、bundleIDに設定した。以下がAppIDをbundleIDとして入力しているところ。名前は編集しています。
で再度ビルドした。先ほどのsigningエラーは出なくなった。が、、どうも実機に焼くところか何かで新たなエラーが出ている。
% flutter run --release Multiple devices found: iphone (mobile) ? 4671xxxxxxxxxxxxxxxxxxxx34e ? ios ? iOS 15.1 19B74 iPod touch (7th generation) (mobile) ? EF6548CA-291A-4848-8EA1-48BB692CC5A2 ? ios ? com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator) Chrome (web) ? chrome ? web-javascript ? Google Chrome 97.0.4692.99 [1]: iphone (4671xxxxxxxxxxxxxxxxxxxxxxx3434e) [2]: iPod touch (7th generation) (EF6548CA-291A-4848-8EA1-48BB692CC5A2) [3]: Chrome (chrome) Please choose one (To quit, press "q/Q"): 1 Launching lib/main.dart on iphone in release mode... Automatically signing iOS for device deployment using specified development team in Xcode project: JWxxxxxxS9 Running Xcode build... Xcode build done. 21.7s Failed to build iOS app Error output from Xcode build: ? 2022-02-05 17:50:55.341 xcodebuild[6245:135119] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/DVTiOSFrameworks/DVTiOSFrameworks-19527/DTDeviceKitBase/DTDKRemoteDeviceData.m:373 Details: (null) deviceType from 46717xxxxxxxxxxxxxxxxxxxx3434e was NULL when -platform called. Object: <DTDKMobileDeviceToken: 0x7f948bf6afe0> Method: -platform Thread: <NSThread: 0x7f948bf0f990>{number = 4, name = (null)} Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide. 2022-02-05 17:50:55.607 xcodebuild[6245:135215] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/DVTiOSFrameworks/DVTiOSFrameworks-19527/DTDeviceKitBase/DTDKRemoteDeviceData.m:373 Details: (null) deviceType from 4671xxxxxxxxxxxxxxxxxxxxxxxx3434e was NULL when -platform called. Object: <DTDKMobileDeviceToken: 0x7f948bf6afe0> Method: -platform Thread: <NSThread: 0x7f948bfab5c0>{number = 8, name = (null)} Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide. 2022-02-05 17:50:55.681 xcodebuild[6245:135215] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/DVTiOSFrameworks/DVTiOSFrameworks-19527/DTDeviceKitBase/DTDKRemoteDeviceData.m:373 Details: (null) deviceType from 4671xxxxxxxxxxxxxxxxxxxxxxx3434e was NULL when -platform called. Object: <DTDKMobileDeviceToken: 0x7f948bf6afe0> Method: -platform Thread: <NSThread: 0x7f948bfab5c0>{number = 8, name = (null)} Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide. ** BUILD FAILED ** Xcode's output: ? Writing result bundle at path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.SqfCOY/flutter_ios_build_temp_dirXe5XyX/temporary_xcresult_bundle Failed to package /Users/<user_name>/lang/flutter/testapp01. Command PhaseScriptExecution failed with a nonzero exit code note: Using new build system note: Planning note: Build preparation complete note: Building targets in dependency order Result bundle written to path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.SqfCOY/flutter_ios_build_temp_dirXe5XyX/temporary_xcresult_bundle Could not build the precompiled application for the device. Error running application on iphone.
Result bundle written to pathと書かれていて、パスに書き込まれたバンドル結果?? うーん分からん。少なくとも上記パスは存在しない
同じコマンドをもう一度打つと今度はメッセージが少なくなっている(がエラーは変わらない)
*略* Running Xcode build... Xcode build done. 21.0s Failed to build iOS app Error output from Xcode build: ? ** BUILD FAILED ** Xcode's output: ? Writing result bundle at path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.sTvHsK/flutter_ios_build_temp_dirSiGCl1/temporary_xcresult_bundle Failed to package /Users/<user_name>/lang/flutter/testapp01. Command PhaseScriptExecution failed with a nonzero exit code note: Using new build system note: Planning note: Build preparation complete note: Building targets in dependency order Result bundle written to path: /var/folders/ky/0l1q46ts4tx2sn7dg9hsjbpw0000gp/T/flutter_tools.sTvHsK/flutter_ios_build_temp_dirSiGCl1/temporary_xcresult_bundle Could not build the precompiled application for the device. Error running application on iphone.
いずれにせよXcodeが出しているエラーなので、flutterのせいというより、Xcodeのビルドオプションか、ターゲットデバイスの設定で何か問題と思われる。CLIで動かさずにXcodeをGUIから動かしたらどうなるか。。
Xcodeでリリース用ビルドをやってみた。一応ビルドができて、AppStoreConnectにもアップロードできた。TestFlightで動くか試してみた。以下がTestFlightの画面、テスターとして自分を加える。
iPhoneのTestFlightで、アップロードしたアプリが表示されるので、開くボタンを押してインストール実施
このバイナリがFlutter的にDebugモードなのかReleaseモードなのか?自分は理解不十分で分かっていない。また、flutterコマンドでRelease用バイナリをXcodeで生成できないといけないのだが、今はそこが成功していない(今回は手動で行った。しかもそれはDebugコードなのか、Releaseコードなのか分かっておらず)
Flutterのドキュメントが大量でちゃんと読んでいなかったが、iOS用のビルド・リリース手順が以下にあった。Xcodeは普通に動いていてあまりCLIで設定変更はやりたくないのだが、、このコマンドを一通り実行しないといけないのだろうか。CLIでやる作業とXcodeでやる作業の切り分けがよくわかっていない。
docs.flutter.dev
上記を読むと、Xcodeで諸々の設定を終えた後で、以下のように、 flutter build ipa と打ち込むようである*2。
Run flutter build ipa to produce a build archive.
後半に書かれている、「Create a build archive with Codemagic CLI tools」の章は、Xcodeを使わず、全部CLIでやりたい場合の手順と理解しました。普段はCLIで動かしたい人間ですが、、ビルド、署名、AppStoreConnectへのアップロードをCLIでやるにはあまりにもトラップが多そうで、ためらってしまう。CLIでコンフィグ変えてしまったら戻すに戻せないような気も。。。
よって、自分が適当にやったアップロードとの違いは、Xcodeから手動でビルドするか、あるいは、flutter build ipaをコマンドで実行するかの違いと理解しました。