20201129のiOSに関する記事は7件です。

閉じられたネットワーク内のiPadを自動で時刻調整できるように設定する

概要

インターネット接続のないLAN内にいるiPadの時刻が徐々にずれてきたので、時刻設定を自動でできるようにしてみた。

MacやiOSで使用するNTPサーバのFQDNはエンタープライズネットワークで Apple 製品を使う - Apple サポートで確認できるので、LAN内にDNSサーバとNTPサーバを設置し、LAN内に設置したNTPサーバを指すようにDNSレコードを設定する。

設定

閉じられたネットワークとインターネットの両方に接続できるマシンを準備。
今回は下記の設定。

  • OS: Ubuntu 20.04.1 LTS
  • IP:
    • (閉じられたネットワーク側)192.168.20.199/24
    • (インターネットに接続できる側)DHCP

unboundのインストールと設定

今回はDNSサーバとしてunboundを仕様(bindだと設定が面倒すぎた)。

sudo apt install unbound -y

設定ファイルは下記のように設定。

/etc/unbound/unbound.conf.d/unbound.conf
server:
        verbosity: 1
        interface: 192.168.20.199
        access-control: 192.168.20.0/24 allow
        use-syslog: yes # DNSクエリの監視用
        log-queries: yes #

        local-data: "time.apple.com IN A 192.168.20.199"
        local-data: "time-ios.apple.com IN A 192.168.20.199"
        local-data: "time-macos.apple.com IN A 192.168.20.199"

python:

remote-control:

forward-zone:
        name: "."
        forward-addr: 8.8.8.8
        forward-addr: 8.8.4.4

time.apple.comtime-ios.apple.comtime-macos.apple.comのAレコードはNTPサーバのIPアドレスを指定する(iPadならtime-macosは不要のはずだけど、とりあえず)。
今回は同一マシンにDNSサーバとNTPサーバを立てるのでinterfaceと同じアドレスを指定しているが、すでに他のNTPサーバがあるならそちらのIPアドレスを指定する。

use-syslog: yeslog-queries: yesはiPadからのDNSクエリを確認するために設定。
上手くいったあとは削除して良い。

設定ファイルの編集が済んだらサービスを再起動。

sudo systemctl restart unbound

NTPサーバのインストールと設定

次にNTPサーバをインストールして設定。

sudo apt install ntp -y

完全に好みだが、基準とするNTPサーバはUbuntuのデフォルトで用意されているものをすべてコメントアウトしてINTERNET MULTIFEED CO.で用意されているものを利用した。

/etc/ntp.conf
#pool 0.ubuntu.pool.ntp.org iburst
#pool 1.ubuntu.pool.ntp.org iburst
#pool 2.ubuntu.pool.ntp.org iburst
#pool 3.ubuntu.pool.ntp.org iburst
server ntp1.jst.mfeed.ad.jp iburst
server ntp2.jst.mfeed.ad.jp iburst
server ntp3.jst.mfeed.ad.jp iburst

# Use Ubuntu's ntp server as a fallback.
#pool ntp.ubuntu.com

こちらも設定後にサービス再起動。

sudo systemctl restart ntp

NTPサーバの動作確認のため、ntpdateをインストールして確認。

sudo apt install ntpdate
$ sudo ntpdate -q 192.168.20.199
server 192.168.20.199, stratum 3, offset -0.000027, delay 0.02574
27 Nov 06:08:09 ntpdate[5915]: adjust time server 192.168.20.199 offset -0.000027 sec

iPadの設定

iPadのWi-Fi設定で、DNSサーバを「手動」で「192.168.20.199」(今回の例では)に設定。

あとはしばらく待てばtime-ios.apple.comへのDNSクエリが来て、自動で時刻が調整されているはず。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【iOS】自社プロダクトを守る。不適切レビューへの対処

リリースしたプロダクトには、ユーザーのレビューが付けられます。

プラットフォーム上に公開するiOSアプリで、悪いレビューがついてしまった際には、
新規ダウンロード数減少への影響を最小限にするため、早めに対応したいものです。

本記事では、PM、PO、ディレクター向けに、
削除できるレビュー削除できないレビューの違いを、
実経験に基づき気づいたことをまとめます。

※最終的な判断は、Apple側に委ねられるため、明確な基準は不明であると認識しております。
※<2020年11月29日地点>のApple利用規約を踏まえ記載しております。

なお、レビューの削除依頼を送る方法に関しては、
@RIwaiさんの、App Storeレビュー返信機能を試して見るをご参照ください。

三行で

1.プラットフォームの特性を理解する
2.削除依頼が認められるレビューとは(申請後〇〇日以内に削除される)
3.消せないレビューへの対応方法


1.プラットフォームの特性を理解する

手塩にかけて制作したアプリに低評価が付くと、なんとかして対応(削除)できないものか、と考えます。
しかし、プラットフォームにおけるユーザーレビューは、公平性が担保されていることが大前提です。
(Amazonや、食べログなどのニュースが話題になりました。公平性が命です。)

よって、 削除対象のレビューは問題があることが前提です。

Apple Depeloperの評価、レビュー、返答では以下の箇所が該当します。

ここでは、

不快な内容、スパム、またはAppleの利用規約に違反するその他のコンテンツ

と表現されています。
では、例えば次のレビューは問題のある内容でしょうか。


★☆☆☆☆
タイトル:使えない
本 文 :広告多すぎ。動かないし落ちる。


結果、問題のあるレビューとはみなされません
(悪意のあるユーザーかもしれませんし、そんなにクラッシュすることはないはず、、、と思っていても)

プラットフォーマーのAppleとしては、アプリに対しての意見はAppleユーザーに対しての有益な情報とみなします。

どんな内容であろうが、個人が感じたことや意見は、尊重されるということです。


2.削除依頼が認められるレビューとは (申請後〇〇日以内に削除される)

前項記載の通り、正当なレビューに認定される範囲は広いです。
では、削除対象となるレビューとはどんなものでしょうか。

App Store Connectで、特定のレビューを削除しようとした際には、
以下のカテゴライズがなされています。


※日本語に翻訳されて語義が曖昧に感じられる、場合は正確に把握したいところです。

以下の4種にカテゴライズされます。

・スパムの可能性があります
・その他
・趣旨がずれています
・不快感を与える内容が含まれています

簡単に内容に触れます。

① 最初のスパムに関しては、意味通り無差別かつ大量にばら撒かれるものであると認識できます。
② その他に関しても文字通り、他3項目に分類されない場合に用いる項目ですね。
③ 趣旨がずれていますに関しては、
当該アプリへの意見ではないことが基本で、派生して以下のようなことにも適応されます。
・アプリに掲載されているコンテンツへの意見(運営元が提供するものではなく、他ユーザーの著作)
ex)〇〇のアップしている動画、くだらない
・そのアプリのジャンル(カテゴリ)への意見
ex)こういうタイプのアプリってやらせが多いよね、うんざり。

あくまで所感ですが、全レビューの中でもこれに分類されるものは多く、レビューで削除対象になる場合が一番多いと感じます。
以下のようなレビューは削除されました。(実際のレビューの意図を汲み、言葉を変更して記載)


★☆☆☆☆
タイトル: 動作に難あり
本 文: オフショアで開発しているんじゃないですか。国内では最近そのような風潮があり残念。


④ 不快感を与える内容が含まれていますは、誹謗中傷が該当すると考えられます。
誹謗中傷とは、一般的には他者の権利を侵害している(名誉毀損や侮辱)かどうかがポイントです。

権利侵害 概要
名誉毀損 公然の場で具体的事実を挙げて、第三者の評判を落とす行為 (例:あいつは不倫している、あいつは前科持ちだ)
侮辱 公然の場で具体的事実を挙げないで第三者の評判を落とす行為(例:性格悪い、落ちこぼれ、気持ち悪い)

低評価のレビューは言葉が暴力的になりがちで、公然の場で具体的事実を挙げて、第三者の評判を落とす行為との線引きが非常に難しいのが実情です。
よってApple側も、不快感を与える内容という表現をされているのだと感じました。
誰に不快感を与えるのかその主語を考ると、他のAppleユーザーが該当するかと考えられます。

結論、客観的な事実(アプリの仕様)に言及していても、言葉から受け取るイメージによっては削除対象になる。
と推察されます。
Apple側からすると、そんな内容のレビューを残していて良いのかとユーザーから思われるからでしょう。

このカテゴリで申請をして、削除されたケースもあります。

そして、上記に該当する疑いがあるレビューを報告した場合、
30分〜1時間以内に削除されるケース(当日)が多くありました。

また、カテゴリを変えての申請が削除と認められるケースもありましたので、2回までのトライは有用と考えられます。


3.消せないレビューへの対応方法

当然ながら、高い品質で、ユーザーが真に求める良いアプリを作ることが一番大事ですが、
レビュー者への真摯な対応も効果的です。

具体的には、レビューへの返信をすることです。

実例として、アプリの機能に関して「ここは改善した方が良い」といった、
星2つの真っ当なレビュー頂いたことがありました。

社内で協議し、その通りに機能改善を行った後、
そのユーザー様に機能改善した旨と、感謝述べる形で返信をしました。

翌日、その方のレビューが消えていて、変わりに★5のレビューが1つ増えていました。

これには、社内の開発メンバーのモチベーション向上に大きく繋がりました。

他にも、良いレビューに良い評価をする、などといった小技もありますが、
公平性を担保するプラットフォームの特性を考えても、良質なプロダクト開発が何より大事なことと感じております。

まとめ

■Apple側の削除基準が完全にわかるわけでは無いので、低評価レビューに関しては以下を行う。
 ・真摯に対応し、レビュー者に返信
 ・グレーなレビュー内容には、問題を報告するで、リポートを行ってみる。

■バージョンごとのレビューを更新(消すこと)もできるが、良質のプロダクト、高いレベルの顧客体験を提供できるよう努力し、低評価レビューへの対応自体をなくすことが一番!


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode12でArchiveビルドがとても長くなった時の調査方法

起こったこと

  • Xcode11.7 -> Xcode12(12.1や12.2でも同様だった)にアップデートしたら、アーカイブビルドがとても長くなった。
    • 具体的には、Xcode11.7で15分程度だったのが、Xcode12.2で3時間程度かかるようになった。
  • bitriseだと60分でタイムアウトするし、これだと運用が厳しいので対策するべく原因調査した。

原因、対策

後述する通りいろいろと調べたところ、原因は下記の通りだった。

  • Xcode12にバンドルされているSwift5.3のコンパイラのOptimization LevelOptimize for SpeedOptimize for Sizeのとき(アーカイブビルドのときに指定されている)のswift コンパイルの挙動が変わっていたため
  • 上記Optimization Levelのときに、コンパイルが特に遅いSwiftファイルが1ファイルあった。
    • 対策としては、このSwiftファイルをコンパイルが速くなるように書き換えた。

この記事のメインテーマは、どうやって上記の原因までたどり着いたかのところで、それを下記します。
もしかしたら、当たり前なことなのかもしれないが、わたしはとても苦戦しました。

調べたこと

アーカイブ時のビルド時のログ出力確認

最初、普通にビルドログ見てたが、それだと、Build Phaseの Compile Source(swiftファイルをコンパイルするフェーズ)の直前のshell script実行のところで止まっていて、そのscript自体は単体ではすぐ終わる処理(単体で実行して確認済み)だったので、ログがちゃんと出ていないように思った。
20201129_1.png

SwiftコンパイラのOptimization Level

デバッグビルドでは問題なかったのと、以前の問題があったので、Archive時のSwiftコンパイラのOptimization Level(Optimize for Speed)が問題なのではと思って、デバッグビルドのOptimization Levelを Optimize for Speed にしたらビルドが遅くなったので、SwiftコンパイラのOptimization Levelが問題であることに気付いた。
※デバッグビルドの方がビルドログが細かく出力されるので、これ以降はデバッグビルドのOptimization Levelを Optimize for Speed にして調査しています。

また、compiler optimization level = Optimize for Size にしたらビルド速くなったら嬉しいなーと思ってやってみたけど、変わらなかった。。。

Swift Other Flag追加してログ出力確認

結果的に今回の調査では役立ったわけではないが、もうちょっとちゃんとビルドログ出力させたいと思って Other Swift Flagsに下記を追加。これでビルドログが詳細に出るようになった。

  • -Xfrontend -warn-long-expression-type-checking=300
    • 型推論に300ms以上かかったらwarning
  • -Xfrontend -warn-long-function-bodies=300
    • コンパイルに100ms以上かかるメソッドをwarning

この辺りは下記の記事を見ながら色々やってみていた。
https://dev.classmethod.jp/articles/investigated_compiletime_swift/
https://techlife.cookpad.com/entry/2017/12/08/124532

ビルドが遅くなっているところを確認

何度やっても下記の赤枠のswiftファイルのコンパイルが遅いので、多分swiftファイルの書き方の問題なんじゃ無いかと思ってきた。
試しに、簡単に直せそうなswiftファイル(10行未満のswiftファイルが含まれた)を全部コメントアウトしても、速くならなかったので、多分この中でも特定のどれかが遅いのだと思ってきた。
qiita20201129-2.png

※このとき、遅くなっているswift ファイルのコンパイル直後に各frameworkのlinkが走っていたので、実はそこが遅いんじゃ無いかと思った(具体的にはBridging-Header.hに @import をいくつか書いてたのでそれが問題なのかもと思った)が、違った。。。

コンパイルが遅くなっているswift ファイルがどれかを特定

上記の赤枠のファイルを選択して、コピペすると、下記のようなテキストがペーストされた。

Showing Recent Messages
CompileSwift normal arm64 /プロジェクトのパス/〜〜〜〜〜/〜〜〜〜〜〜〜.swift (in target '〜〜〜〜〜' from project '〜〜〜〜〜')
    cd /プロジェクトのパス
    /Applications/Xcode12_2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -filelist /var/folders/5t/〜〜〜〜〜〜〜〜〜〜〜〜〜〜/T/sources-4f43a5 -primary-file /プロジェクトのパス/〜〜〜〜〜/〜〜〜〜〜〜〜.swift -emit-module-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名\~partial.swiftmodule -emit-module-doc-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名\~partial.swiftdoc -emit-module-source-info-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名\~partial.swiftsourceinfo -serialize-diagnostics-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名.dia -emit-dependencies-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名.d -emit-reference-dependencies-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名.swiftdeps -target arm64-apple-ios11.0 -Xllvm -aarch64-use-tbi -enable-objc-interop -sdk /Applications/Xcode12_2.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.2.sdk -I /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/APIKit -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/Alamofire -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/AlamofireImage -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/AppAuth -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/BoringSSL-GRPC -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/Cartography -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/Differ -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/GoogleDataTransport -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/JWTDecode -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/MBProgressHUD -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/RxCocoa -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/SwiftGifOrigin -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/YoutubePlayer-in-WKWebView -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜 -F /プロジェクトのパス/Pods/AppsFlyerFramework/iOS -F /プロジェクトのパス/Pods/FirebaseAnalytics/Frameworks -F /プロジェクトのパス/Pods/〜〜〜〜〜/Frameworks -F /プロジェクトのパス/Pods/〜〜〜〜〜/Frameworks -F /プロジェクトのパス/Pods/〜〜〜〜〜/Frameworks -F /プロジェクトのパス/Pods/〜〜〜〜〜/〜〜〜〜〜.embeddedframework -F /プロジェクトのパス/Pods/〜〜〜〜〜 -F /プロジェクトのパス/Pods/〜〜〜〜〜/Build/iOS -F /プロジェクトのパス/Pods/〜〜〜〜〜/Build/iOS -F /プロジェクトのパス -F /プロジェクトのパス/〜〜〜〜〜 -F /プロジェクトのパス/ライブラリ/Frameworks-build -enable-testing -g -module-cache-path /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -swift-version 5 -enforce-exclusivity\=checked -O -D DEBUG -D COCOAPODS -D COCOAPODS -enable-swift3-objc-inference -warn-swift3-objc-inference-minimal -warn-long-function-bodies\=300 -warn-long-expression-type-checking\=300 -serialize-debugging-options -Xcc -working-directory -Xcc /プロジェクトのパス -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/swift-overrides.hmap -Xcc -iquote -Xcc /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/〜〜〜〜〜-generated-files.hmap -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/〜〜〜〜〜-own-target-headers.hmap -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/〜〜〜〜〜-all-non-framework-target-headers.hmap -Xcc -ivfsoverlay -Xcc /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/all-product-headers.yaml -Xcc -iquote -Xcc /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/〜〜〜〜〜-project-headers.hmap -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/include -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜/〜〜〜〜〜.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜/〜〜〜〜〜.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜/〜〜〜〜〜.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/BoringSSL-GRPC/openssl_grpc.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/〜〜〜〜〜/〜〜〜〜〜.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/MK2Router/MK2Router.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/YoutubePlayer-in-WKWebView/YoutubePlayer_in_WKWebView.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/gRPC-Core/grpc.framework/Headers -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Products/Debug-iphoneos/swiftライブラリframework/Headers -Xcc -I/プロジェクトのパス/Pods/Headers/Public -Xcc -I/プロジェクトのパス/Pods/Headers/Public/ライブラリ -Xcc -I/プロジェクトのパス/Pods/Headers/Public/ライブラリ -Xcc -I/プロジェクトのパス/Pods/Firebase/CoreOnly/Sources -Xcc -I/Sources/FBLPromises/include -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/DerivedSources-normal/arm64 -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/DerivedSources/arm64 -Xcc -I/ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/DerivedSources -Xcc -DDEBUG\=1 -Xcc -DCOCOAPODS\=1 -Xcc -DDEBUG\=1 -Xcc -DGPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\=1 -Xcc -DDEBUG\=1 -Xcc -DPB_FIELD_32BIT\=1 -Xcc -DPB_NO_PACKED_STRUCTS\=1 -Xcc -DPB_ENABLE_MALLOC\=1 -target-sdk-version 14.2 -import-objc-header /プロジェクトのパス/〜〜〜〜〜/Bridging-Header.h -pch-output-dir /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/PrecompiledHeaders -pch-disable-validation -module-name 〜〜〜〜〜 -o /ユーザーフォルダのパス/Library/Developer/Xcode/DerivedData/〜〜〜〜〜-ejcjafpdqhgmythgozbispsdrwky/Build/Intermediates.noindex/〜〜〜〜〜.build/Debug-iphoneos/〜〜〜〜〜.build/Objects-normal/arm64/swiftファイル名.o -embed-bitcode-marker


CompileSwift normal arm64 〜〜〜〜が選択したswiftファイル分続く。

上記の、

cd /プロジェクトのパス 
/Applications/Xcode12_2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend ~~~~~

のところをそのままshell(ターミナル)で実行したら普通に実行できた(1ファイルのswiftコンパイルができる)ので、それで赤枠の各swiftファイルのコンパイルを試したところ、ある1ファイルだけ、すごく時間がかかったのでそれでどのファイルがコンパイルが遅いのかがわかった。

swiftファイル内のどの処理が遅いか特定

やり方は色々ありそうだがそれほど苦労しなかった。
実際にやったやり方は、一旦問題のswiftファイルを全部コメントアウトしてみてから、上記のshell上でのswiftコンパイルを実行し、少しずつコメントアウトを復活させながら、shell上でのswiftコンパイルの実行繰り返して特定した。
その結果、あるenum(かなり大きめでいろいろなViewControllerを参照したAssociated Values を持つenum。このswiftファイルとは別のswiffファイル内で定義)を引数で参照している箇所が遅いことが発覚したので、それのenumを参照しないようにすることで問題解決した。

最後に

上記対応後、結果的に多分、2分程度はXcode12にしてからアーカイブが速くなったような気がします。
最初、この問題に遭遇した時は、解決できるのだろうか(できればXcode12がアップデートされたら勝手に解決されないかなとおもった)、、、と思ったが、諦めずに1つ1つの問題の原因に向き合っていけば、解決に近づいていける、、、そう信じたいと思った。解決できてよかった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

guard文まとめてみた

guard文の役割

想定外の状況が起こった時にその処理から抜け出す役割をします。

書き方

guard 条件 else {
   条件を満たさなかったときの処理
   break //returnでも良い
} 条件を満たした時の処理

使ってみた

number2を割る数として割る数に0が入った時、{}内の処理が行われます。
条件式 number2 != 0の時{}外の処理
number2 == 0の時{}内の処理です。

            guard number2 != 0 else{
                answerLabel.text = "割る数には0以外の数字を入れてください"
                return
            }
            kekka = number1 / number2

参考文献

詳解Swift 第5版

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flutter入門メモ:開発環境構築編

経緯

久々に新規でモバイルアプリでも作ろうかと思い、
一人で趣味で作るレベルだと、Swift・Kotlinでそれぞれ構築するのは掛けられる工数的に現実感が無いので、
1ソース系を試してみようかと。

1ソース系は他にも選択肢がありますが、
React Nativeはなんか好みではないのと、Apache Cordovaは嫌な思い出しかないので、
流行ってるFlutterでやれないかなと、公式を見ながら少し試してみる事にしました。
今回は開発環境までのメモ。

確認環境

  • macOS Catalina
  • Essential Essential Phone PH-1 (Android 10)

前提

  • Homebrewがインストールされている。

※今回確認を実施したMacでは、XcodeやIntelliJ、VS Codeが予めインストールされています。

手順

Flutterのインストール。

$ brew install flutter
$ flutter --version
Flutter 1.22.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 1aafb3a8b9 (2 weeks ago) • 2020-11-13 09:59:28 -0800
Engine • revision 2c956a31c0
Tools • Dart 2.10.4

設定の確認と解消

設定の確認をすると色々と怒られるので、一つ一つ確認。

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Mac OS X 10.15.7 19H15 darwin-x64, locale en-JP)

[!] Android toolchain - develop for Android devices (Android SDK version 27.0.3)
    ✗ Flutter requires Android SDK 29 and the Android BuildTools 28.0.3
      To update the Android SDK visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions.
    ✗ Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
[!] Xcode - develop for iOS and macOS (Xcode 12.1)
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install:
        sudo gem install cocoapods
[!] Android Studio (not installed)
[!] IntelliJ IDEA Ultimate Edition (version 2020.2.4)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[!] VS Code (version 1.51.1)
    ✗ Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[!] Connected device
    ! No devices available

! Doctor found issues in 6 categories.

Android Studio (not installed)

Android Studioのインストール。

$ brew install android-studio

設定の確認をすると下記も必要な様子。

[!] Android Studio (version 4.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
  1. Android Studioを起動し、Preferences->Pluginsを選択する。
  2. FlutterとDartをインストールする。

IntelliJ IDEA Ultimate Edition (version 2020.2.4)

  1. IntelliJを起動し、Preferences->Pluginsを選択する。
  2. FlutterとDartをインストールする。

VS Code (version 1.51.1)

extensionからFlutterをインストールする。

Android toolchain - develop for Android devices (Android SDK version 27.0.3)

Android SDK 29及びAndroid BuildTools 28.0.3以降のインストール。

  1. Android Studioを起動し、Configure->SDK Managerを選択する。
  2. Android SDKからAndroid 10.0を選択し、Apply。
  3. SDK ToolsからAndroid SDK build-Toolsを選択し、Apply。

ライセンスの許可を実行し、問題なければ全てyで進める。

$ flutter doctor --android-licenses

Xcode - develop for iOS and macOS (Xcode 12.1)

$ gem update --system
$ sudo gem install cocoapods

Connected device

  1. About phoneからBuild numberを連打して開発者向けオプションを開放し、
    System->Advanced->Developer optionsを選択、
    Developer optionsとUSB debuggingをオンにする。
  2. 端末をつなげる。

設定の再確認

Android Studioのpluginに関してはエラーが出たままだが、

下記によると、使用上は問題なさそう。
https://github.com/flutter/flutter/issues/67986#issuecomment-715452201

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Mac OS X 10.15.7 19H15 darwin-x64, locale en-JP)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)

[✓] Xcode - develop for iOS and macOS (Xcode 12.1)
[!] Android Studio (version 4.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] IntelliJ IDEA Ultimate Edition (version 2020.2.4)
[✓] VS Code (version 1.51.1)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.

感想

doctorの指示に従って対応すれば良いのでだいぶ楽になりましたね。
はるか昔、Android1.6や2.1くらいの時は結構大変だった記憶があったような…。
また、環境構築時にAndroid Studio 3.1の残骸を見て、
Androidアプリの作成は何年も触ってもいないんだなという時間の流れを感じました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

swich文について初歩的なことをかく

スクリーンショット 2020-11-29 8.07.16.png

swich文の書き方

    let number1 = Double(number1TextField.text!) ?? 0
    let number2 = Double(number2TextField.text!) ?? 0
    var kekka :Double = 0
switch calculateSegmentedControl.selectedSegmentIndex{
    case 0:
        kekka = number1 + number2
    case 1:
        kekka = number1 - number2
    case 2:
        kekka = number1 * number2
    case 3:
        guard number2 != 0 else{
            answerLabel.text = "割る数には0以外の数字を入れてください"
            return
        }
        kekka = number1 / number2
      default:
        print("該当なし")
    }

メモ程度なので自分が使用したコードをそのまま載せます。
swich 式 {
case ラベル1:
    文...
case ラベル2:
    文...
default:
文...
}
こんな感じで書く。
式にはcaseで条件分けしたい式を書きます。この場合だとsegmentedControlのIndexを式に入れることで、ラベルに0番目、1番目と指定してそれぞれの処理を書いていきます。

segmentedControler
スクリーンショット 2020-11-29 8.07.16.png
スクリーンショット 2020-11-29 8.07.16.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcodeを使わずUIKitのレイアウトをjsonで書いて複数の実機で同時にHotReloadするライブラリを作った

概要

タイトルの通りです。
SwiftUIが話題になってきている令和の時代にUIKitに焦点を当てたライブラリを作ってみました。
名前はUIKitHotReloadです。
Githubはこちら。

概要

  • レイアウトをjsonで記述します
  • 複数の実機で同時にHotReloadさせることができます
  • 既存のUIKitのレイアウトと組み合わせ可能です
  • Firestoreのsnapshotの機能を使います
  • Releaseビルド時はbundleされたjsonファイルを利用するのでHotReloadしません
  • xibやstoryboardを置き換えるものなのでViewControllerは必要です
  • ボタンタップ時のアクションなどもswiftで記載する必要があります

動き

こんな感じで複数のシミュレータで同時にHotReloadできます。
もちろん複数の実機でも同様にHotReloadします。

より詳細な動画はYouTubeにあげています。
IMAGE ALT TEXT HERE

レイアウトの組み方

以下のような画面の中央に赤丸のviewを表示させるシンプルな画面の例を記します。

ViewController.swift

ViewControllerから読み込みたいViewのjsonを指定します。

ViewController.swift
import UIKit
import UIKitHotReload

final class ViewsViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    // views/sample.jsonを読み込む場合
    self.view.loadHotReload(dirName: "views", jsonFileName: "sample") { result in
      switch result {
      case .failure(let error):
        //読み込み失敗
        print(error.localizedDescription)
      default:
        //読み込み成功
        break
      }
    }
  }
}

views/sample.json

基本的にUIKitのクラス名やパラメータ名と連動したkeyでjsonを記述します。

views/sample.json
{
  "class": "view",
  "background_color": [
    1,
    1,
    1
  ],
  "subviews": [
    {
      "class": "view",
      "background_color": [
        1,
        0,
        0
      ],
      "circle": {
        "rad": 50
      },
      "layout": {
        "center": {
          "x": {
            "v": 0
          },
          "y": {
            "v": 0
          }
        },
        "size": {
          "width": {
            "v": 100
          },
          "height": {
            "v": 100
          }
        }
      }
    }
  ]
}

HotReloadする仕組み

UIKitHotReloadはjsonからUIKitのViewを構築していくトランスパイラとして機能しています。
VSCodeのRun On Scriptのアドオンなどでjsonを保存したらfirestoreにアップロードさせます。
firestoreのリアルタイムにローカル(スマホアプリ)とサーバーのデータを同期する機能により、即時にアプリ内の画面がリロードさせjsonからUIKitのレイアウトを再構築します。
リリースビルドの場合はbundleされたjsonを読み込むためfirestoreと連携はしません。

SwiftUIと比べて

メリット

・iOS13以前でも動く
・既存のUIKitのソースコードと親和性が高い
・一度インストールしたらXcodeすら立ち上げる必要がないので中古のmacbook airでもレイアウトが組める
・複数の実機で同時にHotReloadでレイアウトを確認できるので、一度チームメンバーに配布したら、再配信することなく全員の意見を即時反映させることができる

デメリット

・firestoreの機能が前提
・VSCodeのRun On Script(保存したらスクリプト実行)が前提
・初期設定に手間がかかる
・オンライン環境でないとHotReloadは機能しない
・jsonで補完が効かない
・サポートしているviewの種類が少ない

サポートしているView

UIView
UIButton
UILabel
UIImageView
UITextField
UIScrollView
UIStackView
UITableView
UITableViewCell

その他の例

UIView

UIViewのパラメータを使った実装例です

ViewsViewController.swift
views.json

UIButton

UIButtonを使った実装例です
jsonからswiftの連携をしたボタンタップ時の処理も記述しています

ButtonsViewController.swift
buttons.json

Twitter風

UITableViewの例としてTwitter風のセルを表示させています。

TwitterTimelineViewController.swift
twitter_timeline.json
twitter_timeline_cell.json

今後

初期設定をシンプルにする
サポートするviewの追加
複数人が同時編集できるようにする
テストコードを入れる

終わり

CocoaPodsの登録も初めてでしたが意外と簡単にできるんだなと思いました。
オープンソースのライブラリの作法なんかもよく分かってもらず、ご意見などいただけると嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む