- 投稿日:2021-01-23T23:07:48+09:00
何回もこのコンピュータを信頼しますかと表示されて実機テストができない
- 投稿日:2021-01-23T21:19:14+09:00
AVFoundation 音再生
音再生方法
まず AVFoundation をインポート
viewController.swiftimport UIKit import AVFoundation class ViewController: UIViewController,AVAudioPlayerDelegate { var player :AVAudioPlayer!まず、音ファイルをXcodeに追加。追加するのはここ!!
今回は
umbrella と souziki が入っていますね。
音声を呼び出す用の関数を定義!
viewController.swiftpublic func prepareSound() { let soundFilePath = Bundle.main.path(forResource: "umbrella", ofType: "mp3")! let sound:URL = URL(fileURLWithPath: soundFilePath) do { player = try AVAudioPlayer(contentsOf: sound, fileTypeHint: nil) player?.delegate = self } catch { print("イエラー") } player?.delegate = self player?.prepareToPlay() }viewDidLoad()に関数を記入
viewController.swiftoverride func viewDidLoad() { super.viewDidLoad() prepareSound() }あとは、ボタンなど、呼び出したいところで下記のオードを書けば
viewController.swift@IBAction func button(_ sender: Any) { if ((player?.isPlaying) != nil) { player?.stop() player?.currentTime = 0 } player?.play() }現在、選択私の違いによって出る音の変わる仕組みを製作中。
- 投稿日:2021-01-23T15:26:25+09:00
Firebaseの CloudMessaging での通知実装と Apple Developer Certificates に苦戦したメモ
基本的にはこちらの手順に従う方針だが、既にCertificateを作成していたり、本番用と開発用で違ったり、Bundle ID が違うと動かないなどがあり苦戦したのでメモ。
https://qiita.com/ausssxi/items/89305cdb3935d6f6f2b8全体的に、iOSにおけるプッシュ通知は基本UserNotificationsをimportして使うが、そもそものプッシュ通知を送るバックエンド側のシステムが必要で、それがニフクラモバイルやFirebaseで実装されることが多いっぽい。なおFirebaseのCloud MessagingというのはFirebaseコンソールからユーザーにメルマガみたいにプッシュ通知を送れる仕組みのことっぽい。
主なつまずきポイント
シミュレータでは通知こないっぽい?
まずiOSにおける通知はアプリ起動中はこない模様。
Singing & Capabilities
でPush Notifications
と合わせてBackgound Modes
を追加しているので、アプリが表で起動してないときに通知を送る仕様なのだが、Xcodeで起動させるiPhoneシミュレータではそもそもバックグランドモードが使えないらしい。
FirebaseのCloud Messagingで通知を行うためのCertificateも必要
通知で使うAPNs証明書(.p12ファイル)を作成するために Apple Push Services というCertificate(.cerファイル)を作成する必要がある。Certificate=証明書=.cerファイル=.p12ファイルであり、Firebaseなどの外部で証明書を使う際にはこの.12形式に変換してやらないといけないようだ。
最新のAPNsキー方式ではうまくいかなかった
Firebase公式が推奨しているAPNsキー(.p8ファイル)の方式では機能しなかった。もしかすると Bundle ID が一致してなかったときに試したからかもしれない。試していないがわかりやすそうなQiitaを見つけたので貼っておく。
https://qiita.com/MYamate_jp/items/994a31d5408bc09998bcBundle ID が Firebase とアプリで同じでないといけない
同じプロジェクトでもBundle ID を変えてしまえばApp Store Connectでは別アプリとして認識されリリースできる。Firebaseも2つのアプリでデータを共用することができる。しかしFirebaseへのアプリ登録時のBundle ID と異なるアプリへは、Cloud Messaging を用いたプッシュ通知が送れないっぽい。
実機テストではDevelopmentだが本番ではDistribution
初めに提示したQiitaは実機で通知テストするためにDevelopmentのCertificateを作成していたが、(Xcode11がiOS14に対応しておらず、Xcode12にあげるためにBigSurにあげるのは嫌だったので)本番環境で使うDistributionのCertificateを使って通知のテストをした。幸い、まだ通知機能を実装しているアプリはリリースされていないのでTestflightでインストールしたテスターにしか通知はいかない。
なお本番環境用のAPNsのCertificateは
Sandbox & Production
の方。
Apple Developer Certificates
そもそもの知識
CSR、鍵、証明書、Provisioning Profile については以下の図解がとても分かりやすい。
https://qiita.com/fujisan3/items/d037e3c40a0acc46f618超ざっくりしたあやふやな理解
・DevelopmentとDistributionで2つのCertificate Typeがある
・Developmentは実機テストで使い、DistributionはApp Storeへの配信に使う
・Provisioning Profileに書かれたMac・デバイス・App・機能の組み合わせでないとビルドが許可されていない手元の実機iPhoneにアプリをインストールするのも、App Storeにアプリをリリースするのも、FirebaseのCloud Messagingで通知を送るのも、全部「わたしはAppleに認証されたMac(開発者),iPhoneですよー」という証明をしないといけない。
証明書やそれを生成するための鍵(CSR生成時に作られる?)はMacの中に保存するが、「どの証明書(TEAM)・App ID・デバイス・機能(Capabilities)で実行できるアプリなのか」というプロファイルを書いたProvisioning Profileというものをアプリに持たせ、それをApp Storeに申請することで、App Store Connect側は「あ、はいはい、確かに認証されたMac(TEAM)、App ID、機能の組み合わせねー」としてビルドとして認めてくれるようだ。
なおデバイスについては、あくまでDevelopmentのCertificateで実機テストするためのデバイスのことだと思われ、本番用のDistributionのCertificateを使ってリリース作業を行う場合は特に関係ないと思われる。ただ実機テストをする際に実機に Provisioning Profile がインストールされるそうである。
XcodeのCertificateが消えない問題
直接的には関係ないが、Certificateを作り直したりしていると遭遇。Keychainの証明書や鍵(認証局に証明書を要求するためのCSRと一緒に作られる?)を削除して、ProvisioningProfileを削除しても消えない。右クリックでDeleteしようとしてもダメ出し、Untitledとなっている証明書は存在せず、また日付から特定しようとしてもそれらしきものはない。
Apple Development Certificate の「〇〇の Macbook Pro」と、それに対応する Provisioning Profileは UITest のアプリが勝手に生成するようなので削除しても復活するらしい。誰か助けて。
- 投稿日:2021-01-23T12:08:06+09:00
FIT SDKのMacStaticLibで大きなメッセージを書き込んだときにデコードに失敗する不具合を回避する
TL;DR
FitMesg.h
とFitMesg.mm
を修正してビルドしたlibFitSdkCppiOS.a
とヘッダーファイルを差し替える。
修正内容は記事の末尾。不具合詳細
GARMIN FIT SDKはC言語/C++/Java/C#で提供されているが、同梱されているMacStaticLibを使用することでObjective-Cから使用することが出来、macOSやiOSのアプリから使用することができる。
しかし、このMacStaticLibにはバグがあり、メッセージのサイズが256Byte以上になるとヘッダーに書き込まれるデータ長とファイル末尾のCRCの値がおかしくなり、デコードできないFITファイルが生成されてしまう。
再現コード
FIT SDKに同梱されているサンプルプロジェクトにコードを追加したもの。
https://github.com/rseki-sonix/fit-ios-broken-headerdevice_infoメッセージのproduct_nameとdescriptorに長い文字列を追加するとデコード処理に失敗するようになる。
原因
Objective-CからC++ FIT SDKを使用するためのラッパークラス
FitEncode
はヘッダに書き込むデータ長を書き込んだメッセージ長から積算している。このメッセージ長の型が
FIT_UINT8
(UINT8のtypedef)になっており、256Byte以上の長さだとオーバーフローしてしまう。https://github.com/rseki-sonix/fit-ios-broken-header/blob/master/usr/local/include/FitMesg.h#L25-L26
そのため、256Byte以上のメッセージが書き込まれるたびにヘッダーのデータ長が255Byte分短くなる。
また、ファイル末尾のCRCもそのデータ長をもとに計算されているためCRCもおかしくなってしまう。生成済みのFITファイルを修復する
生成されたFITファイルはデータ長とCRCだけがおかしいため、適切なデータ長とCRCを書き込めばデコードすることができる。
ファイルサイズからヘッダ長(14Byte)と末尾CRCの長さ(2Byte)を引いた値を計算する。
ヘッダーの内容についてはFit Protocolを参照。今回生成されたファイルは453Byteのためデータ長は
453 - 14 - 2 = 437 = 0x01B5
となる。
CRCは自分で計算してもよいが、FitCSVToolに-dオプションを追加すると計算した数値が表示されるためそれを用いる。
今回は0x03A9
だった。
書き換えるとFitCSVToolでデコードできるようになる。MacStaticLibを修正する
GARMIN Forumsでは"your own risk"でFitMesgを修正してもいいかもとのこと。
単純にメッセージサイズの型をUINT16に変更することで正しいデータ長とCRCを持つFITファイルを生成できる。
以下の二箇所の変更が必要。cpp/FitMesg.h#include "fit_mesg_definition.hpp" @interface FitMesg : NSObject // - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg; // - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef; - (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg; - (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef; @end #endif /* FIT_MESG_H */cpp/FitMesg.mm@implementation FitMesg // - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg - (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg { return [self Write:file forMesg:mesg withDef:FIT_NULL]; } // - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef - (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef { fit::MesgDefinition mesgDefOnNull; // FIT_UINT8 mesgSize = 1; FIT_UINT16 mesgSize = 1; FIT_UINT8 fieldSize = 0; FIT_UINT8 byte;修正した静的ライブラリは以下の方法で行った。