- 投稿日:2019-05-29T15:45:18+09:00
ReactNative実行時のエラー解決メモ
react nativeを0.57.3から0.59.8に上げて実行したらエラーがたくさん出たので解決方法をメモしておきます。
android
Could not get unknown property 'mergeResourcesProvider' for object of type com.android.build.gradle.internal.api.ApplicationVariantImpl.
https://github.com/wix/react-native-navigation/issues/4757#issuecomment-468133753
上記コメント通りに対応すれば解決しました。
metro.config.jsファイルを作成するとありますが、0.59の正式リリースで必要なくなったみたいなので作らなくて大丈夫です。
また、バージョンはいきなり全て最新にすると依存関係でハマったりするので、メジャーバージョンを少しづつあげていく方がいいと思います。Execution failed for task ':app:processDebugResources'. Android resource linking failed /Users/<USER_NAME>/.gradle/caches/transforms-1/files-1.1/appcompat-v7-28.0.0.aar/6f6de8a5350930056a96225b06ab7a16/res/values-v28/values-v28.xml:9:5-12:13: AAPT: error: resource android:attr/dialogCornerRadius not found. /Users/<USER_NAME>/<PROJECT_NAME>/android/app/build/intermediates/incremental/mergeDebugResources/merged.dir/values-v28/values-v28.xml:11: AAPT: error: resource android:attr/dialogCornerRadius not found. /Users/<USER_NAME>/.gradle/caches/transforms-1/files-1.1/drawee-1.10.0.aar/603dac14beab9d235ac515ad5b5f1fe7/res/values/values.xml:3:5-58:857: AAPT: error: resource android:attr/fontVariationSettings not found. /Users/<USER_NAME>/.gradle/caches/transforms-1/files-1.1/drawee-1.10.0.aar/603dac14beab9d235ac515ad5b5f1fe7/res/values/values.xml:3:5-58:857: AAPT: error: resource android:attr/ttcIndex not found. error: failed linking references.ググってみるとcompileSdkVersionを上げると解決するらしい。27だったので28にして実行したら解決した。
ちなみにtargetSdkVersionも上げると別のエラーがいろいろと…
いつか上げなきゃいけない日が来ますが今はとりあえず動けばいいのでそのままで。androidはとりあえず上記のエラーだけで起動しました。動作確認も特に問題なく一安心。
iOS
iOSは色々と厄介で何度もキャッシュ消したりして時間がかかりました。
** BUILD FAILED ** The following commands produced analyzer issues: Analyze /Users/<USER_NAME>/<PROJECT_NAME>/node_modules/react-native/ReactCommon/jsi/jsi.cpp normal x86_64 Analyze /Users/<USER_NAME>/<PROJECT_NAME>/node_modules/react-native/ReactCommon/yoga/yoga/Yoga.cpp normal x86_64 Analyze Base/RCTModuleMethod.mm normal x86_64 (3 commands with analyzer issues) The following build commands failed: CompileC /Users/<USER_NAME>/<PROJECT_NAME>/ios/build/CRIA/Build/Intermediates.noindex/RNFirebase.build/Debug-iphonesimulator/RNFirebase.build/Objects-normal/x86_64/RNFirebaseMessaging.o RNFirebase/messaging/RNFirebaseMessaging.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler (1 failure)iOSだとエラーで止まると最後にこのようなログが出てきますが、ここには具体的なエラーの内容が書かれてないのでそのままググってもあまり意味ないです。
大量のログを少しずつ遡ってerror catch
あるいは1 error generated.
と出力されている直前の行にエラーの中身が出力されています。pch was compiled with module cache path ~ , but the path is currently ~
ios/Build/PROJECT_NAME/ModuleCache.noindexフォルダを削除すると解決。
'folly/Portability.h' file not found
https://github.com/facebook/react-native/issues/24192#issuecomment-479497777
ここのpod 'Folly'
以下をPodFileに追加してpod install
する。
それでもエラーが出る場合はios/PodsフォルダとPodfile.lockを削除して再度pod install
する。info ** BUILD SUCCEEDED ** info Installing build/CRIA/Build/Products/Debug-iphonesimulator/<APP_NAME>.app An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=2): Failed to install the requested application An application bundle was not found at the provided path. Provide a valid path to the desired application bundle. Print: Entry, ":CFBundleIdentifier", Does Not Exist error Command failed: /usr/libexec/PlistBuddy -c Print:CFBundleIdentifier build/CRIA/Build/Products/Debug-iphonesimulator/<APP_NAME>.app/Info.plist Print: Entry, ":CFBundleIdentifier", Does Not Exist . Run CLI with --verbose flag for more details. error Command failed with exit code 1.あー…ここでこのエラーですか…
ネットにある色んな解決方法を大方試してみるも解決せず…埒が明かないのでXcodeからアプリを実行してみる。(実行するときはxcworkspaceから実行しないとエラーになるので注意)
……何事もなくアプリが起動
なんでよ…と思いつつ再度コマンドで実行してみるもやっぱりダメ。この後更に色々試しましたが、結局解決できなかったのでめんどくさいけどXcodeから実行することにしましたorz
- 投稿日:2019-05-29T15:22:00+09:00
iOS シミュレータ を オレオレ証明書なサーバに接続する手順
iOS シミュレータで localhostに接続する
(今更ATSかよっと思いますがご愛嬌) info.plistにATS対象除外リストに入れるのが普通のやり方だと思いますが、証明書をシミュレータにインストールして、信頼できるサーバとして登録したほうが早そう。ATSの設定をしてもうまく行かなかったので。ただのリンク集です。
手順
- オレオレ証明書をこんな感じにシミュレータに入れる
- シミュレータの設定appを起動 > General > Profile > localhost を install
- こんな感じでlocalhostを信頼する
そのほか
ATS調査の時に使ったリンク集がこちら。
https://www.gettoby.com/p/rk8t8x16qrmsTOBYというgoogle chrome 拡張。便利ですねコレ。
- 投稿日:2019-05-29T14:46:01+09:00
Optionalの比較
オプショナルの比較
オプショナルの値の比較
オプショナル変数を比較する場合、unwarpする必要がある
var i: Int? if let i = i { if i == 0 { print("0") } else { print("0ではない") } } else { print("nil") }もちろんすべてのケースでそれぞれ処理する必要があるなら別だが、1以上の場合のみラベルを表示するとかになると
let isHidden = i > 0
だけで良い比較2
String?の.countやisEmpty の場合
こちらも基本同じです。
func hoge2(_ val: String?) { if val?.count == 0 { print("0文字です") } if val?.isEmpty == true { print("0文字です2") } if varl?.isEmpty == false { print("0文字じゃないかnilです") } } hoge2("1") print("^^^^ \"1\"の結果 ^^^^") hoge2("") print("^^^^ \"\"の結果 ^^^^") hoge2(nil) print("^^^^ nilの結果 ^^^^")結果
文字列がある = 1 ^^^^ "1"の結果 ^^^^ 0文字です 0文字です2 ^^^^ ""の結果 ^^^^ ^^^^ nilの結果 ^^^^
- 投稿日:2019-05-29T12:56:53+09:00
UITableViewのデリゲートメソッドの呼び出しを別のオブジェクトに転送する方法
UITableViewのデリゲートメソッドの呼び出しを
tableView.delegate
で指定したオブジェクト以外に転送したかったので、その方法を調べました。 1要件として、既存の
class Delegate: NSObject, UITableViewDelegate
が存在する状態で、Delegate
で宣言しているデリゲートメソッドはそのメソッドが呼び出され、宣言していないメソッドはAnotherDelegate
に転送してほしいということがありました。一つの方法として、
Delegate
上で全てのデリゲートメソッドを定義しておき、その各メソッド内部で転送先のオブジェクトの同名メソッドを呼び出すというのを考えたのですが、面倒な上にUITableView
の一部のデフォルト動作がデリゲートメソッド自体の有無で切り替わるようになっているらしく、この方法だと定義しなくてもいいメソッドのデフォルト動作がうまく作動しないことがわかりました。そこで、セレクタの呼び出しをそのまま別のオブジェクトに転送しようと考えその方法を検索しました。すると、
NSProxy
を利用した方法などが見つかるのですが、残念ながらNSProxy
中で使われているNSInvocation
というクラスがSwiftではunavailableとされており、利用できません。そこで、以下の方法で実装しました。
前提
- Xcode 10.2.1
- Swift 5.0.1
- iOS 12.2
セレクタについての説明は省略します。
TL;DR
コード
final class Delegate: NSObject, UITableViewDelegate { /// 転送先のオブジェクト private let proxy: NSObject init(with proxy: NSObject) { self.proxy = proxy } override func responds(to aSelector: Selector!) -> Bool { // `Delegate` のインスタンスか `proxy` がセレクタを処理できるなら `true` を返す return Delegate.instancesRespond(to: aSelector) || proxy.responds(to: aSelector) } override func forwardingTarget(for aSelector: Selector!) -> Any? { // `Delegate` のインスタンスが処理できないセレクタは `proxy` に処理させる return proxy } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("Selected: \(indexPath)") } } final class AnotherDelegate: NSObject, UITableViewDelegate { func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { print("Deselected: \(indexPath)") } } tableView.delegate = Delegate(with: AnotherDelegate())適当にセルをタップした時の出力
Selected: [1, 3] Deselected: [1, 3] Selected: [1, 1] Deselected: [1, 1] Selected: [2, 0]1. 既存の
Delegate
に転送先を保存するためのプロパティを作成するfinal class Delegate: NSObject, UITableViewDelegate { /// 転送先のオブジェクト private let proxy: NSObject init(with proxy: NSObject) { self.proxy = proxy } /* ... */ }まず、転送先のオブジェクトを保存するプロパティ
proxy
を既存のDelegate
に追加しておきます。2.
Delegate
にresponds(to aSelector: Selector!)
を実装するfinal class Delegate: NSObject, UITableViewDelegate { /* ... */ override func responds(to aSelector: Selector!) -> Bool { // `Delegate` のインスタンスか `proxy` がセレクタを処理できるなら `true` を返す return Delegate.instancesRespond(to: aSelector) || proxy.responds(to: aSelector) } /* ... */ }
responds(to aSelector: Selector!)
は、NSObjectProtocol
が定義しているメソッドで、あるオブジェクトが指定したセレクタを処理できるかを返します。今回の要件の場合、
Delegate
のインスタンスがaSelector
を処理できるproxy
がaSelector
を処理できるのいずれか一方が真なら全体としてセレクタを処理できる事になります。
そこでそれぞれの処理の可能性を、
で調べています。
3.
Delegate
にforwardingTarget(for aSelector: Selector!)
を実装するfinal class Delegate: NSObject, UITableViewDelegate { /* ... */ override func forwardingTarget(for aSelector: Selector!) -> Any? { // `Delegate` のインスタンスが処理できないセレクタは `proxy` に処理させる return proxy } /* ... */ }次に、
Delegate
が処理できなかったデリゲートメソッドの呼び出しをproxy
に転送する必要があります。Objective-Cのランタイムでは、あるオブジェクトが実装していないセレクタがそのオブジェクトに通知されると、
forwardingTarget(for aSelector: Selector!)
というメソッドが呼び出されます。 (本当はもっと色々呼び出されるのですが、今回関係するのはこのメソッドだけです。)このメソッドは引数(
aSelector
)に実装していないセレクタが渡され、戻り値でそのセレクタを処理できる別のオブジェクトを返す必要があります。今回の要件の場合、
Delegate
のインスタンスで処理できないセレクタはproxy
が処理できるので、無条件にproxy
を返しています。「処理できないセレクタが呼び出された時にこのメソッドが呼ばれるのであれば、
responds(to aSelector: Selector!)
を実装する必要はないのではないか」と思われるかもしれませんが、両方実装しないと正常に動作しません(forwardingTarget(for aSelector: Selector!)
が呼ばれない)。おそらくUITableView
の内部でデリゲートメソッドを呼び出す際にdelegate.responds(to aSelector: Selector!)
を呼び出し、true
でない場合にはそのデリゲートメソッドの呼び出し自体を省略しているからだと考えられます。4. 通常通りデリゲートメソッドを実装する
final class Delegate: NSObject, UITableViewDelegate { /* ... */ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("Selected: \(indexPath)") } } final class AnotherDelegate: NSObject, UITableViewDelegate { func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { print("Deselected: \(indexPath)") } } tableView.delegate = Delegate(with: AnotherDelegate())ここまで実装しておけば、あとは通常通りデリゲートメソッドを実装することで呼び出されます。
TL;DRに書いたコードでは、
Delegate
にtableView(_:didSelectRowAt:)
を実装し、AnotherDelegate
にtableView(_:didDeselectRowAt:)
を実装していますが、どちらも正常に呼び出されています。デリゲートメソッドの呼び出しの優先度は、
Delegate
→AnotherDelegate
の順です。もし両方のクラスに同じデリゲートメソッドを定義した場合、Delegate
のものが優先的に呼ばれます。自分はObjective-Cの理解が全然甘いので、もし何か間違ったことを言っていれば教えてください。
参考文献
- instancesRespond(to:) - NSObject | Apple Developer Documentation
- responds(to:) - NSObjectProtocol | Apple Developer Documentation
- forwardingTarget(for:) - NSObject | Apple Developer Documentation
- forwardInvocation: - NSObject | Apple Developer Documentation
- SwiftでNSProxyを使った開発ができなくなってた - しめ鯖日記
- メッセージの転送を理解する - Qiita
タイトルにはUITableViewとありますが、UIKitの他のデリゲートでも同じことができます ↩
当たり前ですが、ここで
Delegate
のインスタンスがaSelector
を処理できるかを調べるのにself.responds(to: aSelector)
やsuper.responds(to: aSelector)
を使うことはできません。前者は無限ループになるし、後者はそもそもスーパークラスに定義されているわけではないので意味が通りません。(多分)この記事のような目的のためにNSObject.instancesRespond(to:)
というクラスメソッドがあるんだと思います。 ↩
- 投稿日:2019-05-29T12:31:17+09:00
Pythonista で QRコードを作ってuiに表示する
はじめに
買ったまま1年ぐらい(もっとかも)使ってなかった Pythonista 3。もったいないので公式ドキュメントをみながらあれこれ試してる。Qiitaはいつも見てるばかりなので、書いてみることにした。
やること - QRコードを作る
iOSアプリとして使いたいのでuiViewを使う。テキストフィールドに変換したい文字列をいれて、ボタンを押すとQRコードを作る。
完成イメージ
QRコードの作り方
qrcodeというライブラリを使うと簡単にQRコードがつくれる。それをconsoleに出すのは、こうやればいいので簡単。
sample.pyimport qrcode img = qrcode.make('http://flapro.net/') #ここにQRコードにしたい文字列を入れる show.image()ui.ImageViewに表示するには、PILからImageに変換する必要がある。
Pythonista公式サイトのフォーラムにやりかたが載っていたので使わせてもらった。pil2ui.py# pil <=> ui def pil2ui(imgIn): with io.BytesIO() as bIO: imgIn.save(bIO, 'PNG') imgOut = ui.Image.from_data(bIO.getvalue()) del bIO return imgOut完成したソース
qr.pyimport ui import io from PIL import Image import qrcode def getQR(sender): img = pil2ui(qrcode.make(sender.superview['textfield'].text)) sender.superview['imageView'].image = img # pil <=> ui def pil2ui(imgIn): with io.BytesIO() as bIO: imgIn.save(bIO, 'PNG') imgOut = ui.Image.from_data(bIO.getvalue()) del bIO return imgOut v = ui.load_view() v.present('sheet')参考
- 投稿日:2019-05-29T12:13:30+09:00
app Extensionの設定周り
AppExtensionについて
iOS8のApp Extensionsをつくってみる(Share 実装編)
App Extensions プログラミングガイドをざっくりまとめた
の記事が分かりやすいです。
簡単にいうと、アプリ間連携の仕組みになります。概念
ホストとなるアプリとExtensionバイナリをAppGroupでグルーピングして共有ファイル/データへアクセスできるようにします。
手順
前提
・すでにプロジェクトが出来上がっていること前提。
・AppleDeveloperアカウントを持っていること1.Extensionスキームを追加
Targets欄の"+"ボタンを押して、Action Extensionのスキームを追加。
2.本体アプリにバイナリ追加
GeneralタブのEmbedBinaryの"+"ボタンをタップし、先ほど追加したExtensionのスキームを追加
3.Entitlementsファイルを設定
CapabilitiesタブでAppGroupをOnにするとEntitlementsファイルが作成されます。
ホストアプリのスキームとExtensionのスキーム両方に設定。4.AppGroupを設定
AddGroupsの"+"ボタンをタップしてGroupを追加します。
ホストアプリのスキームとExtensionのスキーム両方に設定。5.AppleDeveloperでAppGroupを追加
Group名は先ほどプロジェクトで追加したGroup名
6.ビルドするAppIDとAppGroupをつなげる
ホストアプリとExtension両方に設定。
設定後、プロビジョニングプロファイルを作成し、ダウンロード。7.Extensionのplist設定
BundleDisplayNameとNSExtensionActivationRuleを設定。参考にした記事
https://www.techotopia.com/index.php/Sharing_Data_Between_a_WatchKit_App_and_the_Containing_iOS_App
- 投稿日:2019-05-29T11:34:41+09:00
「」内の文字が省略されるUILabelを作る
ときどき、文字列の中央を省略するのではなく、「」内の文字を省略して表示してほしいという要件が来ることがあります。正攻法でやるとなかなか難しそうなので、こんな方法を考えました。
文頭「
中の文字列
」文末
のように、3つのUILabel
に分割し、Stack View等でまとめる- 省略したい中央の
UILabel
のContent Compression Resistance Priority
を、ほかの2つのUILabel
より小さいな値にするコード上では特別することはありませんが、文全体が動的に変わるような場合は適宜分割し、それぞれのラベルに振り分ける必要があります。
ちなみにもし、一行ではなく複数行でこれをやりたいというケースだった場合...どうしたらいいんでしょうね(笑)