- 投稿日:2020-02-28T20:22:46+09:00
【iOS】UISegmentedControlの見た目を変える(iOS13対応)
概要
UISegmentedControlの見た目を変えたいなぁ - Qiita
さんを参考に、iOS13に対応したカスタムUISegmentedControlを紹介します。コード
今回書いたカスタムクラスを丸ごと貼ります。
プロジェクト内にコピペしてください。FlatSegmentedControl.swiftimport UIKit class FlatSegmentedControl: UISegmentedControl { private var segmentItemWidth: CGFloat = 0 private var underline: CALayer = CALayer() private var themeColor: UIColor = UIColor(red: 41/255, green: 171/255, blue: 227/255, alpha: 1) private var layers: [CATextLayer] = [] convenience init() { self.init(frame: CGRect.zero) } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setUp() } public override init(frame: CGRect) { super.init(frame: frame) setUp() } private func setUp() { self.tintColor = UIColor.clear underline.backgroundColor = themeColor.cgColor self.layer.addSublayer(underline) for index in 0 ..< self.numberOfSegments { let textLayer = CATextLayer() textLayer.string = self.titleForSegment(at: index) textLayer.alignmentMode = CATextLayerAlignmentMode.center textLayer.contentsScale = UIScreen.main.scale textLayer.fontSize = 17 layers.append(textLayer) self.layer.addSublayer(layers[index]) } decorateSelectedItem() } func setThemeColor(_ color: UIColor) { themeColor = color underline.backgroundColor = themeColor.cgColor rewriteTextLayer() } override func setTitle(_ title: String?, forSegmentAt segment: Int) { super.setTitle(title, forSegmentAt: segment) layers[segment].string = title } private func rewriteTextLayer() { for index in 0 ..< self.numberOfSegments { let layer = layers[index] if index == self.selectedSegmentIndex { layer.font = UIFont.boldSystemFont(ofSize: layer.fontSize) layer.foregroundColor = themeColor.cgColor } else { layer.font = UIFont.systemFont(ofSize: layer.fontSize) layer.foregroundColor = UIColor.black.cgColor } } } override func layoutSubviews() { super.layoutSubviews() layoutLayerFrame() } private func decorateSelectedItem() { underline.frame.origin.x = CGFloat(self.selectedSegmentIndex) * segmentItemWidth rewriteTextLayer() } private func layoutLayerFrame() { segmentItemWidth = self.frame.width / CGFloat(self.numberOfSegments) underline.frame = CGRect(x: CGFloat(self.selectedSegmentIndex) * segmentItemWidth, y: self.frame.height - 4, width: segmentItemWidth, height: 4) if #available(iOS 13, *) { if let defaultLayers = self.layer.sublayers { defaultLayers.forEach { (layer) in layer.isHidden = true } } layer.cornerRadius = 0 } for index in 0 ..< self.numberOfSegments { layers[index].frame = CGRect(x: segmentItemWidth * CGFloat(index), y: 8, width: segmentItemWidth, height: self.frame.height - 12) if #available(iOS 13, *) { layers[index].isHidden = false } } if #available(iOS 13, *) { underline.isHidden = false } decorateSelectedItem() } }使い方
基本
Storyboardの例で進めます。
UISegmentedControlを選んで設置します。
FlatSegmentedControlクラスを使うようにします。
もし、コードでタイトル設定する場合はこのように。@IBOutlet weak var flatTab: FlatSegmentedControl! { didSet { flatTab.setTitle("1番目タブ", forSegmentAt: 0) flatTab.setTitle("2番目タブ", forSegmentAt: 1) flatTab.setTitle("3番目タブ", forSegmentAt: 2) } }Actionにはタブ選択時の動作を書きます。これもUISegmentedControlと同じ。
@IBAction func onTabTap(_ sender: FlatSegmentedControl) { switch sender.selectedSegmentIndex { case 0: // 1番目が選択された時にすること case 1: // 2番目が選択された時にすること case 2: // 3番目が選択された時にすること default: // デフォルト挙動 } }色を変える
setThemeColor
というメソッドを生やしてあるので、このようにUIColorを渡してください。@IBOutlet weak var flatTab: FlatSegmentedControl! { didSet { flatTab.setThemeColor(UIColor.cyan) } }
- 投稿日:2020-02-28T17:58:17+09:00
Multiple targets match implicit dependency for linker flags エラーの解決法
FirebaseでGoogleSignInを導入したらエラーが発生。
share extensionを使った時も同じようなエラーが出た。
解決法
podfileを修正
以下を追加
pod 'GTMSessionFetcher'解決後
# Uncomment the next line to define a global platform for your project platform :ios, '10.0' use_frameworks! def google_utilites pod 'GoogleUtilities/AppDelegateSwizzler' pod 'GoogleUtilities/Environment' pod 'GoogleUtilities/ISASwizzler' pod 'GoogleUtilities/Logger' pod 'GoogleUtilities/MethodSwizzler' pod 'GoogleUtilities/NSData+zlib' pod 'GoogleUtilities/Network' pod 'GoogleUtilities/Reachability' pod 'GoogleUtilities/UserDefaults' pod 'GTMSessionFetcher' end target 'myApp' do google_utilites pod 'Firebase/Auth' pod 'Firebase/Database' pod 'Firebase/Storage' pod 'Firebase/Analytics' pod 'GoogleSignIn' end target 'shareExtension' do google_utilites pod 'Firebase/Auth' pod 'Firebase/Database' pod 'Firebase/Storage' end
- 投稿日:2020-02-28T17:34:13+09:00
謎リジェクトされてしまった件について+対応
初めて以下のようなリジェクトをくらいました。
差出人: Apple Other - Other Hello, We are unable to continue this app’s review because your Apple Developer Program account is currently under investigation for not following the App Store Review Guidelines’ Developer Code of Conduct. Common practices that may lead to an investigation include, but are not limited to: ・Inaccurately describing an app or service ・Misleading app content ・Engaging in inauthentic ratings and reviews manipulation ・Providing misleading customer support responses ・Providing misleading responses in Resolution Center ・Engaging in misleading purchasing or bait-and-switch schemes ・Engaging in other dishonest or fraudulent activity within or outside of the app During our investigation, we will not review any apps you submit. Please do not create a new developer account or make any app transfers while waiting for the investigation to be completed. Once we have completed our investigation, we will notify you via Resolution Center. Due to the nature of the investigation you will be ineligible to receive an expedited review until the investigation is completed. We do not require any additional information from you at this time, nor do we have any additional details to share. We appreciate your continued patience during our investigation. Best regards,差出人:アップル
その他-その他
こんにちは、お使いのApple Developer Programアカウントは、App Storeレビューガイドラインのデベロッパー行動規範に従っていないため、現在調査中のため、このアプリのレビューを続行できません。
調査につながる可能性のある一般的な慣行には、以下が含まれますが、これらに限定されません。
・アプリまたはサービスの記述が不正確
・誤解を招くアプリコンテンツ
・不正な評価とレビュー操作の実施
・誤解を招くカスタマーサポートの対応を提供する
・解決センターで誤解を招くような回答を提供する
・誤解を招く購入または餌とスイッチのスキームに従事する
・アプリの内外で他の不正行為または詐欺行為に従事する調査中、送信されたアプリは審査されません。調査の完了を待っている間は、新しいデベロッパーアカウントを作成したり、アプリを転送したりしないでください。調査が完了すると、解決センター経由で通知します。調査の性質上、調査が完了するまで、迅速なレビューを受ける資格はありません。
現時点では、お客様からの追加情報は必要ありません。また、共有する詳細情報もありません。調査中、しばらくお待ちいただきますようお願いいたします。
不正なんかしてませんよ!!
ちょっとググってみたら、昨年にデベロッパが大量検挙?されたようでその名残なのか
現在もちょこちょこ起きている様子。https://forums.developer.apple.com/thread/116331
https://qiita.com/gureta/items/b21b264dfa95051e67bb
https://qiita.com/sowtara/items/101614f8183d5b3c1419
https://www.imgn.ltd/posts/developer-account-under-investigation/一旦ストアからアプリを削除して申請し直すというのが対策として挙げられています。
ほんとにそれでいいのかな〜と疑問に思いつつも・ストアからアプリ削除
・bundleID変更
・ストアにアプリ新規作成して再申請を行ってみたところ、次の日には審査をしてもらい、無事(?)に別の要因でリジェクトされました。
審査自体をしてもらっただけでもありがたい。長い人は半年とか待ってたみたいなので…
(50ドル返せよって感じですよね)現在はこの対応で進むという認識で良さそうです。
なんとなく釈然としない感じではありますが。
- 投稿日:2020-02-28T17:02:10+09:00
アプリの署名を更新
開発者の証明書の期限が切れるなどで証明書を更新すると、過去に作った
ipa
ファイルが開発用端末で使えなくなる。
ビルドし直すという手もあるが、時間が経っているとビルド環境が変わっている可能性が高い。Fastlaneを
ipa
を再度署名することができる。コマンド例FASTLANE_SKIP_UPDATE_CHECK=1 && \ FASTLANE_OPT_OUT_USAGE=1 && \ fastlane sigh resign myapp.ipa \ --use_app_entitlements \ --signing_identity 'iPhone Distribution: Runo Sahara.' \ --provisioning_profile "$HOME/Library/MobileDevice/Provisioning Profiles/myapp.Today.mobileprovision" \ --provisioning_profile "$HOME/Library/MobileDevice/Provisioning Profiles/myapp.mobileprovision"確認方法
次を確認したくなる。
- 有効期限が正しいか。
- Entitlements が正しく、ワイルドカードで無いこと。
QuickLook
ipa
やmobileprovision
ファイルをmac上でQuickLookするツールがある。
Github: https://github.com/ealeksandrov/ProvisionQLインストールコマンド例brew cask install provisionql
Codesign
Codesign で entitlement を確認できる。
コマンド例unzip myapp.ipa codesign -d --entitlements :- Payload/myapp.app/関連コマンド
自動化するために役に立つコマンド。
現在の状態で使えるidentity一覧security find-identity -v -p codesigningアプリ側のidentitycodesign -vv -d Payload/myapp.appmobileprovisionの情報を取得security cms -D -i embedded.mobileprovision > temp.plist APPNAME=`/usr/libexec/PlistBuddy -c "Print :AppIDName" temp.plist` TEAMID=`/usr/libexec/PlistBuddy -c "Print :TeamIdentifier:0" temp.plist` APPID=`/usr/libexec/PlistBuddy -c "Print :Entitlements:application-identifier" temp.plist` EXPIRATIONDATE=`defaults read temp.plist ExpirationDate`(
ipa
を解凍してembedded.mobileprovision
をfindすれば、アプリ側のものが確認できる。)
- 投稿日:2020-02-28T17:02:10+09:00
iOSアプリの署名を更新
開発者の証明書の期限が切れるなどで証明書を更新すると、過去に作った
ipa
ファイルが開発用端末で使えなくなる。
ビルドし直すという手もあるが、時間が経っているとビルド環境が変わっている可能性が高い。Fastlaneを
ipa
を再度署名することができる。コマンド例FASTLANE_SKIP_UPDATE_CHECK=1 && \ FASTLANE_OPT_OUT_USAGE=1 && \ fastlane sigh resign myapp.ipa \ --use_app_entitlements \ --signing_identity 'iPhone Distribution: Runo Sahara.' \ --provisioning_profile "$HOME/Library/MobileDevice/Provisioning Profiles/myapp.Today.mobileprovision" \ --provisioning_profile "$HOME/Library/MobileDevice/Provisioning Profiles/myapp.mobileprovision"確認方法
次を確認したくなる。
- 有効期限が正しいか。
- Entitlements が正しく、ワイルドカードで無いこと。
QuickLook
ipa
やmobileprovision
ファイルをmac上でQuickLookするツールがある。
Github: https://github.com/ealeksandrov/ProvisionQLインストールコマンド例brew cask install provisionql
Codesign
Codesign で entitlement を確認できる。
コマンド例unzip myapp.ipa codesign -d --entitlements :- Payload/myapp.app/関連コマンド
自動化するために役に立つコマンド。
現在の状態で使えるidentity一覧security find-identity -v -p codesigningアプリ側のidentitycodesign -vv -d Payload/myapp.appmobileprovisionの情報を取得security cms -D -i embedded.mobileprovision > temp.plist APPNAME=`/usr/libexec/PlistBuddy -c "Print :AppIDName" temp.plist` TEAMID=`/usr/libexec/PlistBuddy -c "Print :TeamIdentifier:0" temp.plist` APPID=`/usr/libexec/PlistBuddy -c "Print :Entitlements:application-identifier" temp.plist` EXPIRATIONDATE=`defaults read temp.plist ExpirationDate`(
ipa
を解凍してembedded.mobileprovision
をfindすれば、アプリ側のものが確認できる。)
- 投稿日:2020-02-28T10:26:46+09:00
Core Haptics - カスタムハプティックパターンの作成と再生
Core Hapticsは、iOS 13で新たに追加された「ハプティック(触覚)パターンを作成し、再生する」ためのフレームワークです。ついにTaptic Engineを開発者が制御するためのAPIが公開されたというわけです。1
従来手法(UIFeedbackGenerator)との違い
Taptic Engineが初めて搭載されたのはiPhone 6sで、ハプティックパターンの再生自体は、iOS 10で追加された
UIFeedbackGenerator
により以前から可能でした。
UIFeedbackGenerator
は抽象クラスで、UIImpactFeedbackGenerator
,UINotificationFeedbackGenerator
,UISelectionFeedbackGenerator
の3種類の具象クラスがあります。それぞれの実装例を以下に示します。
UIImpactFeedbackGenerator
let impactFeedbacker = UIImpactFeedbackGenerator(style: .heavy) impactFeedbacker.prepare() impactFeedbacker.impactOccurred()
UINotificationFeedbackGenerator
let notificationFeedbacker = UINotificationFeedbackGenerator() notificationFeedbacker.notificationOccurred(.success)
UISelectionFeedbackGenerator
let selectionFeedbacker = UISelectionFeedbackGenerator() @IBAction func sliderChanged(_ sender: UISlider) { selectionFeedbacker.selectionChanged() }上記のコード例からもわかる通り、いずれの場合もあらかじめ決められたタイプのハプティックパターンを再生するというものでした。
Core Hapticsの場合は、このハプティックパターンをカスタマイズできる点が従来手法と大きく違う点です。
Core Hapticsの実装
まずはCore Hapticsの全体感を掴むため、基本的な実装の流れを見てみましょう。
1. インポート
CoreHapticsをインポートします。
import CoreHaptics2. エンジンをスタートする
エンジン(
CHHapticEngine
)を初期化し、let engine = try! CHHapticEngine()
start()
メソッドを呼んでスタートします。try! engine.start()3. ハプティックパターンを生成する
ハプティックイベント(
CHHapticEvent
)を生成し(詳細は後述)、let audioEvent = CHHapticEvent(eventType: .audioContinuous, parameters: [ CHHapticEventParameter(parameterID: .audioPitch, value: -0.15), CHHapticEventParameter(parameterID: .audioVolume, value: volume), CHHapticEventParameter(parameterID: .decayTime, value: decay), CHHapticEventParameter(parameterID: .sustained, value: 0) ], relativeTime: 0) let hapticEvent = CHHapticEvent(eventType: .hapticTransient, parameters: [ CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness), CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity) ], relativeTime: 0)複数のハプティックイベントを組み合わせてパターン(
CHHapticPattern
)を生成します。let pattern = try! CHHapticPattern(events: [audioEvent, hapticEvent], parameters: [])4. ハプティックパターンを再生する
CHHapticEngine
のmakePlayer(with:)
メソッドにパターンを渡して、プレイヤー(CHHapticPatternPlayer
)オブジェクトを生成します。let player = try! engine.makePlayer(with: pattern)
CHHapticPatternPlayer
のstart(atTime)
メソッドを呼んでハプティックを再生します。try! player.start(atTime: CHHapticTimeImmediate)ハプティックイベント(CHHapticEvent)
Core Hapticsとはカスタムハプティックパターンをつくって再生できるフレームワークです。そして、そのパターン(
CHHapticPattern
)は複数のハプティックイベント(CHHapticEvent
)から構成され2、ハプティックイベントは発生タイミング、イベントタイプ、長さ、そして複数のイベントパラメータ(
CHHapticEventParameter
)より規定されます。つまり、カスタムなハプティックパターンをつくる重要な構成要素である
CHHapticEvent
を規定する各種プロパティとCHHapticEventParameter
を理解することがCore Hapticsを使いこなす鍵となります。というわけで、以下で
CHHapticEvent
を規定する各種要素について順番に解説していきます。ハプティックイベントタイプ(CHHapticEvent.EventType)
CHHapticEvent
は次のようなイニシャライザを持ち、第1引数にイベントタイプ(CHHapticEvent.EventType
)を渡せるようになっています。init(eventType type: CHHapticEvent.EventType, parameters eventParams: [CHHapticEventParameter], relativeTime time: TimeInterval)これはその名の通りハプティックイベントのタイプを決めるもので、次の4種類が定義されています。
static let audioContinuous: CHHapticEvent.EventType static let audioCustom: CHHapticEvent.EventType static let hapticTransient: CHHapticEvent.EventType static let hapticContinuous: CHHapticEvent.EventType
audio〜
はオーディオによるフィードバック、haptic〜
は触覚によるフィードバックです。hapticタイプの方は"Transient"と"Continuous"とがありますが、"Transient"とは「一時的な」という意味で、
hapticTransient
は短いインパルス的なハプティックを、hapticContinuous
は任意の長さを持ち、ループするハプティックを示します。CHHapticEventの発生タイミング(relativeTime)
上述した
CHHapticEvent
のイニシャライザは、第3引数にイベントを開始する時間(relativeTime
)を指定できるようになっています。名前に"relative"とある通り、絶対時間ではなく、ハプティックパターン内における相対時間(単位は秒)で指定します。
let hapticEvent = CHHapticEvent( eventType: type, parameters:params, relativeTime: 0.1) // 0.1秒後に開始CHHapticEventの長さ(duration)
CHHapticEvent
はハプティックイベントの長さを指定するduration
プロパティを持ちます。var duration: TimeIntervalContinuousなイベントタイプの場合は、本プロパティに
0.0
より大きい値をセットしておかないと再生時にクラッシュします。3最大値は30秒です。
イベントパラメータ(CHHapticEventParameter)
前述の
CHHapticEvent
のイニシャライザの第2引数に配列で渡すのが、イベントパラメータ(CHHapticEventParameter
)です。let audioEvent = CHHapticEvent( eventType: type, parameters: [param1, param2], // [CHHapticEventParameter] relativeTime: 0)イニシャライザは次のように定義されており、
init(parameterID: CHHapticEvent.ParameterID, value: Float)第1引数にパラメータの種類を示すID(
CHHapticEvent.ParameterID
)、第2引数にパラメータの値(Float
)を渡します。let pitch = CHHapticEventParameter(parameterID: .audioPitch, value: -0.15) let volume = CHHapticEventParameter(parameterID: .audioVolume, value: 0.5)
CHHapticEvent.ParameterID
には多くの種類があるので、ここでは主なものを紹介します。haptic用
イベントタイプが
hapticTransient
,hapticContinuous
なハプティックイベント専用のパラメータIDが次の2つです。static let hapticIntensity: CHHapticEvent.ParameterID static let hapticSharpness: CHHapticEvent.ParameterID
hapticIntensity
:ハプティックの強さを0.0
〜1.0
で指定hapticSharpness
:ハプティックの鋭さを0.0
〜1.0
で指定audio用
イベントタイプが
audioContinuous
,audioCustom
なハプティックイベント専用のパラメータIDが次の4つです。static let audioVolume: CHHapticEvent.ParameterID static let audioPitch: CHHapticEvent.ParameterID static let audioPan: CHHapticEvent.ParameterID static let audioBrightness: CHHapticEvent.ParameterID
audioVolume
:音量を0.0
〜1.0
で指定audioPitch
:音のピッチを-1.0
(低い)〜1.0
(高い)で指定audioPan
:音の位置(定位)を-1.0
(左)〜1.0
(右)で指定。デフォルトは0.0
(中央)audioBrightness
:音の高周波成分を0.0
〜1.0
で指定。デフォルトは1.0
(高周波成分を減らさない)共通
audio, haptic共通で"Continuous"なイベントタイプに使えるパラメータのIDとして、次のようなものがあります。それぞれハプティックイベントの波形を細かく調整するためのパラメータです。
static let attackTime: CHHapticEvent.ParameterID static let decayTime: CHHapticEvent.ParameterID static let releaseTime: CHHapticEvent.ParameterID static let sustained: CHHapticEvent.ParameterIDAHAP
AHAP (Apple Haptic and Audio Pattern)はハプティックパターンを定義するJSONライクなファイルフォーマットです。次のような構造でパターンを定義できます。
以下にAHAPファイルの例を示します。4
{ "Version": 1.0, "Metadata": { "Project" : "Haptic Sampler", "Created" : "5 June 2019", "Description" : "An effect that builds in sharpness and intensity." }, "Pattern": [ { "Event": { "Time": 0.0, "EventType": "HapticContinuous", "EventDuration": 1.7, "EventParameters": [ { "ParameterID": "HapticIntensity", "ParameterValue": 1.0 }, { "ParameterID": "HapticSharpness", "ParameterValue": 0.5 } ] } }, { "ParameterCurve": { "ParameterID": "HapticIntensityControl", "Time": 0.0, "ParameterCurveControlPoints": [ { "Time": 0, "ParameterValue": 0.0 }, { "Time": 1.1, "ParameterValue": 0.5 }, { "Time": 1.7, "ParameterValue": 0.0 } ] } }, ...(略) ] }この定義のうち
Event
キーはCore HapticsのCHHapticEvent
に相当し、その配下のTime
キーはrelativeTime
プロパティ、EventType
キーはeventType
プロパティ、EventDuration
キーはduration
、EventParameters
キーはeventParameters
プロパティに相当します。またEventParameters
キー配下の配列に入る要素はCHHapticEventParameter
に相当します。こうしてみれば、AHAPというフォーマットはハプティックパターン(CHHapticPattern
)の実装をそのままJSONに落とし込んだだけであり、難しくはありません。JSONフォーマットなので、AHAPは通常のテキストファイルとして閲覧・編集でき、Xcodeプロジェクトへの追加方法も他のリソースと同様です。
Core Hapticsは、このAHAPファイルからハプティックパターンを読み出して、再生することができます。
AHAPファイルからの再生
AHAPファイルを読み込んでハプティックパターンを再生する実装方法は非常にシンプルです。
エンジン(
CHHapticEngine
)を初期化し、let engine = try! CHHapticEngine()開始します。
try! engine.start()あとは
CHHapticEngine
のplayPattern(from:)
メソッドを呼び、引数にAHAPファイルのURL
を渡すだけです。try! engine.playPattern(from: URL(fileURLWithPath: path))以上でAHAPファイルからハプティックパターンを再生することができます。
サンプルコードのダウンロード
本記事は2019年9月に発売した書籍「iOS 13の新機能をざっくり把握する本」からの転載です。同書籍は現在は100円で販売しています。
「iOS 13の新機能をざっくり把握する本」の電子版をなんと!100円にしてみました。
— Shuichi Tsutsumi (@shu223) January 23, 2020
理由:
・iOS ○と題された本は時間経過で非常に売れにくくなる
・「100円なら買う」層はどれぐらいいるのかの実験
・本が売れたときの通知がくると単純に嬉しい
・(続)https://t.co/aRqpnHp6vHまたCore Hapticsは実際に手元で試してみないと文章だけでは伝わりにくいと思います。上記記事やWEBに転がっている情報で十分実装できるとは思いますが、サクッと試してみたい方はBOOTHにてサンプルも100円で販売しているので投げ銭がてらよろしければご利用ください。
https://shu223.booth.pm/items/1461791
カスタムパターンを生成するサンプルと、AHAPファイルを再生するサンプルが入っています。
Core Hapticsはオーディオによるフィードバックも扱うので、厳密にはTaptic Engineを制御するだけではありません。 ↩
実際にはハプティックパターンを構成する要素としては他に
CHHapticParameterCurve
やCHHapticDynamicParameter
といったものがあります。 ↩ただし、
sustained
パラメータにfalse(0.0
)をセットしておくと、Continuousなイベントタイプに対してduration
が0.0
でも再生可能です。 ↩Appleの"Haptic Sampler"というサンプルコードに付属している
Inflate.ahap
というファイルから抜粋したものです。 ↩
- 投稿日:2020-02-28T06:22:17+09:00
iOS13.3.1の実機でadmobバナーを表示できなかった件
やりたかったこと
iOS向けのアプリケーション作成に手を出しはじめたのですが、admobによる広告をつけようとしたときの件です。
公式のスタートガイド(https://developers.google.com/admob/ios/banner?hl=ja) に従い進めたところ、
シミュレータでのテスト広告表示まで問題なく確認できたが、実機(iPad mini 4)でのテストで躓いた部分を書きます。前提/背景
admobによる広告表示のため、Xcodeのプロジェクトを作成した後に、CocoaPodsを用いて
Google-Mobile-Ads-SDK
をインポートしました。公式ガイドの通りに実装をしてiPhoneSE, iPhone8のシミュレータでテスト広告の表示まで順調に確認できてました。
実機でのテストにおけるランタイムエラー
しかし、いざ実機でアプリケーションを動かそうとしたときに問題が発生しました。
ビルドは成功するのだが、実行時エラーでアプリケーションが落ちてしまう事象に遭遇しました。
- エラーメッセージは下記の通りです(一部)。
dyld: Library not loaded: @rpath/GoogleUtilities.framework/GoogleUtilities
Referenced from 〜以下略原因
iOS 13.3.1 以降はfree developerの作成したアプリでは、ダイナミックフレームワークを拒否するようで、実行時にエラーが起きるらしいです。
詳しく理解できていないのですが、Googleの提供するフレームワークはOSアップデートにより、開発用アカウントの作成したアプリでは動かないみたいです。対応
Podfileの下記部分を変更し、
pod update
を行ったところ無事実機での動作を確認できました。target 'xxx' do # Comment the next line if you don't want to use dynamic frameworks -use_frameworks! +use_modular_headers!記事作成時に気がついたんですが、思いっきり該当するコメントありますね...
# Comment the next line if you don't want to use dynamic frameworks
もしかしたら上記の変更ではなく、コメントアウトだけで動作するのかもしれないですね。開発者登録していないアカウント(下記参照先の原文におけるfree developer)で起こる事象のようなので、
きちんと年貢を納めていれば起こらないエラーなのでしょうね。多分事象が起こる対象が限定されることから、日本語記事があまり見つかりませんでした。
私のような駆け出しの方が躓くようなことがあった時に助けになれば幸いです。環境
- Xcode: Version 11.3.1
- iPad mini 4: システムバージョン 13.3.1
参照先
- https://stackoverflow.com/questions/60249693/application-crash-when-calling-method-firebaseapp-configure-in-a-real-device/60303927#60303927
- https://github.com/firebase/firebase-ios-sdk/issues/4723
- 投稿日:2020-02-28T06:22:17+09:00
admobの広告を実機で表示する際にエラーが起きたときの対処
やりたかったこと
iOS向けのアプリケーション作成に手を出しはじめたのですが、admobによる広告表示を実機で確認しようとしたとき、
下記のエラーに見舞われましたが、なんとか表示まで持っていけたという話です。公式のスタートガイド(https://developers.google.com/admob/ios/banner?hl=ja) に従い進めたところ、
シミュレータでのテスト広告表示まで問題なく確認できたが、実機(iPad mini 4)でのテストで躓いた部分を書きます。前提/背景
admobによる広告表示のため、Xcodeのプロジェクトを作成した後に、CocoaPodsを用いて
Google-Mobile-Ads-SDK
をインポートしました。公式ガイドの通りに実装をしてiPhoneSE, iPhone8のシミュレータでテスト広告の表示まで順調に確認できてました。
実機でのテストにおけるランタイムエラー
しかし、いざ実機でアプリケーションを動かそうとしたときに問題が発生しました。
ビルドは成功するのだが、実行時エラーでアプリケーションが落ちてしまう事象に遭遇しました。
- エラーメッセージは下記の通りです(一部)。
dyld: Library not loaded: @rpath/GoogleUtilities.framework/GoogleUtilities
Referenced from 〜以下略原因
iOS 13.3.1 以降はfree developerの作成したアプリでは、ダイナミックフレームワークを拒否するようで、実行時にエラーが起きるらしいです。
詳しく理解できていないのですが、Googleの提供するフレームワークはOSアップデートにより、開発用アカウントの作成したアプリでは動かないみたいです。対応
Podfileの下記部分を変更し、
pod update
を行ったところ無事実機での動作を確認できました。target 'xxx' do # Comment the next line if you don't want to use dynamic frameworks -use_frameworks! +use_modular_headers!記事作成時に気がついたんですが、思いっきり該当するコメントありますね...
# Comment the next line if you don't want to use dynamic frameworks
もしかしたら上記の変更ではなく、コメントアウトだけで動作するのかもしれないですね。開発者登録していないアカウント(下記参照先の原文におけるfree developer)で起こる事象のようなので、
きちんと年貢を納めていれば起こらないエラーなのでしょうね。多分事象が起こる対象が限定されることから、日本語記事があまり見つかりませんでした。
私のような駆け出しの方が躓くようなことがあった時に助けになれば幸いです。環境
- Xcode: Version 11.3.1
- iPad mini 4: システムバージョン 13.3.1
参照先
- https://stackoverflow.com/questions/60249693/application-crash-when-calling-method-firebaseapp-configure-in-a-real-device/60303927#60303927
- https://github.com/firebase/firebase-ios-sdk/issues/4723