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

数値の丸め方について

数値を丸めたい!

UISliderのvalueを取得した際、小数第5位まで表示されてしまったため数値の丸め方についてまとめました。

方法1 formatを使用する

howToChangeDigits
let number = 12.34567

print(String(format: "%.0f", number))   // -> "12"
print(String(format: "%.1f", number))   // -> "12.3"
print(String(format: "%.2f", number))   // -> "12.35"
print(String(format: "%.3f", number))   // -> "12.346"

結果より、四捨五入して丸められていることがわかります。
丸めた後のデータ型は、String型になります。

方法2 round()を使用する

howToChangeDigits
let number = 12.34567

print(round(number)                  // -> 12.0
print(round(number * 10) / 10)       // -> 12.3
print(round(number * 100) / 100)     // -> 12.35
print(round(number * 1000) / 1000)   // -> 12.346

formatを使用した時と同様に四捨五入されます。
丸めた後のデータ型はDouble型またはFloat型になります。特に型を指定せずにnumberを定義した場合はDouble型になります。
round()の代わりにfloor()を使用すると切り捨て、ceil()を使用すると切り上げて丸めることができます。

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

ドッグフーディング用にiOSアプリからslackにフェードバックをする方法

Debug中のアプリをSlackに簡単にスクショとか動画をメッセージ付きで投稿できる
AppFeedback-iosを入れる

SDKの導入

Carthageでの導入

Cartfileに以下を追記する

github "https://github.com/yahoojapan/AppFeedback-ios"
carthage update

Build PhasesのLink Binary With LibrariesからAppFeedback.frameworkを追加

スクリーンショット 2019-10-25 19.09.47.png

リリースするバージョンには表示しないようにするため、
Build PhasesからRun Scriptで以下を追加

CopyFrameworks.png

if ["${CONFIGURATION}" != "Release" ]; then
  /usr/local/bin/carthage copy-frameworks
fi

Input Files

$(SRCROOT)/Carthage/Build/iOS/AppFeedback.framework

Bridging HeaderにSDKを追加

スクリーンショット 2019-10-30 12.50.36.png

まだ、Briding Headerがない場合は適当にObject-Cのファイルを追加するとBridging Headerを追加するかどうか聞かれるので追加する。その後Obj-Cのファイルは削除

スクリーンショット 2019-10-25 18.36.00.png

Briding HeadeファイルにAppFeedBackを追加

#import <AppFeedback/AppFeedback.h>

実装

AppDelegateに以下のように記載

import AppFeedback


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ……

    #if DEBUG
        AppFeedback.configure(withSlackToken:"<your token>", slackChannel:"<slack channel id>")
    #endif

    // ……
}

もし、SceneDelegateに対応している場合

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        AppFeedback.configure(withSlackToken: "foo", slackChannel: "hoge")
        AppFeedback.readyFeedbackGesture()
        AppFeedback.readyScreenShot()
        guard let _ = (scene as? UIWindowScene) else { return }
    }

slackのtokenはログインした状態でここのcreate tokenから取得する。
チャンネルIDはslackのチャンネルを右クリックでコピーすると分かります。

これで表示完了!!
スクリーンショット 2019-11-05 17.54.53.png

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

ドッグフーディング用にiOSアプリからslackにフィードバックをする方法

Debug中のアプリをSlackに簡単にスクショとか動画をメッセージ付きで投稿できる
AppFeedback-iosを入れる

SDKの導入

Carthageでの導入

Cartfileに以下を追記する

github "https://github.com/yahoojapan/AppFeedback-ios"
carthage update

Build PhasesのLink Binary With LibrariesからAppFeedback.frameworkを追加

スクリーンショット 2019-10-25 19.09.47.png

リリースするバージョンには表示しないようにするため、
Build PhasesからRun Scriptで以下を追加

CopyFrameworks.png

if ["${CONFIGURATION}" != "Release" ]; then
  /usr/local/bin/carthage copy-frameworks
fi

Input Files

$(SRCROOT)/Carthage/Build/iOS/AppFeedback.framework

Bridging HeaderにSDKを追加

スクリーンショット 2019-10-30 12.50.36.png

まだ、Briding Headerがない場合は適当にObject-Cのファイルを追加するとBridging Headerを追加するかどうか聞かれるので追加する。その後Obj-Cのファイルは削除

スクリーンショット 2019-10-25 18.36.00.png

Briding HeadeファイルにAppFeedBackを追加

#import <AppFeedback/AppFeedback.h>

実装

AppDelegateに以下のように記載

import AppFeedback


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ……

    #if DEBUG
        AppFeedback.configure(withSlackToken:"<your token>", slackChannel:"<slack channel id>")
    #endif

    // ……
}

もし、SceneDelegateに対応している場合

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        AppFeedback.configure(withSlackToken: "foo", slackChannel: "hoge")
        AppFeedback.readyFeedbackGesture()
        AppFeedback.readyScreenShot()
        guard let _ = (scene as? UIWindowScene) else { return }
    }

slackのtokenはログインした状態でここのcreate tokenから取得する。
チャンネルIDはslackのチャンネルを右クリックでコピーすると分かります。

これで表示完了!!
スクリーンショット 2019-11-05 17.54.53.png

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

【SwiftUI】画像のリサイズ

画像の表示

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
    }
}

スクリーンショット 2019-11-12 15.03.57.png

大きすぎるのでリサイズ

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
            .frame(width: 50.0, height: 50.0, alignment: .leading)
    }
}

ちゃんとリサイズされません

スクリーンショット 2019-11-12 15.05.16.png

.resizable()を付ける

Image をリサイズする際には .resizable() をつけなければならないみたいです。

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
            .resizable()
            .frame(width: 50.0, height: 50.0, alignment: .leading)
    }
}

スクリーンショット 2019-11-12 15.05.34.png

これでリサイズされました。

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

後輩養成のすすめ。~あの辛い徹夜ラッシュをもうしないために~

1.はじめに

1.1 経緯

年代によって大きく技術力は変わります。僕は学生ですので会社では年代は関係ないのかもしれませんが、プログラミングを必要としない世界(例えば非IT企業、研究室、中高学校)では大きく変わってしまうのです。もちろん一定数そうゆう人は入ってきます。学校ではパソコン関連の同好会みたいな部署が学園祭のアプリや動画を作っていました。僕の学校で問題だったのは人が足りないということ、そして学年によって差が多いところでした。

1.2 なにが問題?

まずは人が足りないということです。学校でやってるアプリとかっていうのは企業の真似事ですからアプリはデザインの人が仕様書作ってみんなで共同作業を...って感じですし、動画は絵コンテから映像化...ここからここまでは○○で...って感じでやるわけですよ。でも人が足りなければできることも少ない、でもやりたい、だから一人でやる。っていう感じに一人に背負わされるわけです。学生なのに労働基準法に抵触(学生だから適法だけども)してるわけですね(笑)

そして二つ目は代によって差があるということです。学校なので留年しない限り進級して卒業します。生憎、これでも進学校ですので高校3年生は学園祭には参加しないのです。そして学園祭は4月の終わりにやるので入ってきてすぐの中学1年生はどちらかというとお客さん側です。
つまりは中2、中3、高1、高2で作り上げます。もっと言うと学園祭は4月の終わりということで準備は前年度になるわけです。今は2019年11月ですから、次は2020年4月です。準備は今年度なんですね。準備は今の中1、中2、中3、高1でやるってことですね。中1はまだ一年を経験していないので見習いです。この状態でもやばいわけです。

lRtTSQg.gif

えー。取り乱しました。つまりは実質、全校の技術者の半分で行うわけです。そしてその差が開くとどうなるかといいますと...。

A期技術者a「よっしゃ、めっちゃ技術力あるで!すごいの作ったろ!」
その年の学校「すげぇー!」
ーーーA期引退ーーー
その年の学校「今年もすごいの作るんやろ?」
B期技術者b「よし、がんばるぞ...まずは前の年のコードは...わからん」
B期技術者c「わからん」
B期技術者d「わからん」
B期技術者bcd「やーめた」
A期技術者a「俺たちの努力が...一代だけ...」
その年の学校「あーあ」

ということになりかねません。というかなりました。(入学する前の学園祭アプリがたびたび途切れてます)そして、今まさにこの状況でこのままいけば僕たちがA期、一個下がB期を演じることになります。(幸い、僕の代は技術力が高いです)

1.3 解決策

講座を開講して技術者ではない人も取り込んで全体的に技術力をアップさせます。ここで気を付けたところ、失敗したところ、成功したところをまとめます。

2.技術者養成講座の歩み

2.1 2019年4月

そのときは全校が学園祭ムードに包まれていました。僕は中3になってすぐの時でした。前年度の体育祭のときに先輩にTwitterを特定され、Androidができると知られた僕はAndroidのアプリを一人で作っていました。正直、技術力は劣らないと思っていましたし、もちろん成功すると思っていました。しかし、いつまでたってもホーム画面が完成しないそうで「Activityは順番に作っていく」僕にとっては一個目の画面が来ないのでなにもできませんでした。先に他の画面をつくればそれぞれへIntentをつなぐ処理を書き忘れそうで怖かったですし、一度書いたコードは自分が書いたコードであっても解読に時間がかかっていましたのでできるだけ順番につくっていました。結果から言うと1週間の睡眠時間は10時間に達していませんでした。このとき、モンスター(魔材)とお友達どころか親友になりました。アプリは学園祭前一週間にはリリースしていました。ですが、画像を多く使うという理由で一部のくそスぺ端末ではOut of memory連発。また、徹夜しました。

2.2 2019年5月

ゴールデンウイークは毎日15時間は寝てました。このさなか、アプリを担当する部署の長になりました。ありがとうございます。同時に「技術者養成講座」(以下、養成講座)の話が同期の動画部署の長からありました。そのひとは僕以上の社畜で、いろんな仕事を掛け持ちしてました。もう、辛い思いをするのはやめようということで他の部署もまとめてこの講座をすることになりました。

2.3 2019年7月

この月に開催しようと思いましたが全然準備できてなくて延期になりました。

2.4 2019年8月

中国にいました。https://qiita.com/Cyber_Hacnosuke/items/e67df2b02cdd7b3e98c1

2.5 2019年9月

技術者ではない人も人員を増やすことにしようと決めました。ここで問題になったのはパソコンの貸し出しです。非技術者のなかにがパソコンを持っていない人が大半でしょう。また、技術者のなかでもデスクトップのみの人もいました。学校にパソコン室はあるのですが、Win8でexe等の実行ファイルは一切実行できない、ダウンロードしたファイルはシャットダウンすると削除...となかなかに難しかったです。

2.6 2019年10月

学校に政府からの補助金でかったマウスのパソコンがあるのが判明。すぐさま交渉にいきました。用途と合致している(研究者を育成するという政府の目的と合致?)ので使用可になりました。22台ほどありました。この確認が済んだ後、安心して中間テストに臨めたのはよかったです。中間テスト後には選択制の外部演習がありました。それが終わった後そのレポートとその演習の発表プレゼン、養成講座、学生研究で押しつぶされそうになりましたが、魔材の力で乗り切りました。幸い、養成講座の準備は8月からしていたので間に合いました。講座の募集が終わりました。全部で39人の応募があり、貸し出し台数はぴったり22台でした。なにかの集計間違えだと思ったのをいまでも覚えています。こんなにひとが集まるとは思いませんでした。このうち、アプリの講座を取ったのは11人で動画部署の12人に続いて2番目の多さでした。

2.7 2019年11月2日

土曜授業の終了後高2フロアにいき準備をしました。そして開講。結果はまた後で。

3. 講座の成功と失敗

3.1 内容

講座内容は以下です。

  • 挨拶
  • 自己紹介
  • OSってなに
  • byteと文字
  • 拡張子ってなに
  • プログラミングに必要なもの エディタ 開発環境
  • プログラミングサイクル
  • カウントアプリを作ろう
  • 変数
  • メソッド
  • イメージピッカーを作ろう

終わらないのを前提でもし理解が早かったらまずいので長めに設定しました。

3.2 失敗

あえて失敗から言いますと、

  • 時間が足りねぇ

のみです。カウントアプリを作り終えるところまでは行きたかったのですが途中までで、プログラミングは数行書いただけ...

3.3 成功

それでも楽しく授業はできました。かなり、わかりやすかったと反響はいただいています。プログラミングもっとしたかった?と聞いてみるとこれでもいいと言ってくれました…ありがとう!文字の解説では「1byte文字と2byte文字を今説明したけど、なにか気づいた?そう!全角と半角だよ!」といったときにみんなが驚いて納得したようでよかったです。途中、Fateのセイバー派か凛派かで生徒と戦争(?)になりましたが、アニメやラノベ、小説のネタを入れて面白く解説できました。プログラミングの続きをしたい人はぜひ同好会へ!と宣伝することでいまでは37人もの人が所属しています。ちなみに僕はアルトリア・ペンドラゴンちゃんが大好きです。とくにメイドオルタ。

4.なにをすればいいか

まず、激務を自分のせいだと思って抱え込まないのが大切です。予算が足りない、人が足りない、時間が足りない...そういったことを上に訴えることによって僕たちは(学校で)講座を開くことができました。では授業内容にはどのような配慮が必要でしょうか?

4.1 授業内容の配慮

初心者も交じっていればそのレベルに合わせるのが必要でしょう。最低レベルに合わせるということです。でも、上級者や経験者はつまらないと思ってしまいます。個人的な感情ですが、自分が知ってることを先生が自慢げに話すと、「先生ってそんな感じなんだ...」という感じになってしまいます。なので、みんなをアッと驚かせるコラムをいれることで「え!そうゆうことだったの?」と興味を持ってもらうことができます。また、このような内容は身近なものかつあまり知られていないことにすべきでしょう。僕の場合これが「1byte文字が半角、2byte文字が全角」というものでした。そしてこれは特に初心者向けにやったほうがいいことですが、プログラミングの先入観や固定概念を捨ててもらう必要があります。したような結果も出ています。(自社調べ)

○○中高の陽キャラに聞いた!プログラミングのイメージ(自社調べ)
3位「パソコンメガネ」
「陰キャラ?(笑)」「ウザい」「アニオタ」
2位「0と1の羅列」
「2進法?」「指が全部で2本しかない人の末路」
1位「ハッキング」
「危ない」「社会の敵」「暗い部屋」「緑色の文字」「Matrix」「一瞬でのっとり」「○ね」

こういった考えをなくし、プログラミングのプロセスを説明するというのが必要になってきます。そしてよく上級者が初心者がやってしまうのは「文法教えて課題」「ソースコード書かせて解説の繰り返し」です。これは時には中級者にも反感をかいます。理由としては言い方を考慮せずに言えば「初心者は思っているよりバカ」ということです。そもそも教える側にたてばそれだけで一般レベルから大きく外れています。僕たちなら別の言語に結びつけたりしてすぐ覚えますが初心者は頼るもの、すなわちプールサイドがない状態で泳いでるのです。説明しましょう、1からいや0から!そしてソースコードをガンガン書くのも同様の理由でよくないです。僕たちは単語帳のようにソースコードのフレーズを覚えられますが、それができない人は非常におおいです。書ききったとしてもそれはあなたの模範解答を映してる可能性が高いです。

  1. まとめ ということで、徹夜ラッシュ回避のため講座を開講したという話でした。https://twitter.com/Cyber_Hacnosuke
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]オーディオクリップ セッティング メモー

Unityマニュアル一通り

Force To Mono

これを有効にすると、マルチチャンネルオーディオはパックする前にミックスダウンされモノラルトラックにされます。
結論:いつ(雑音で?)使われるんでしょう!!! 使ったことありません!(以降もなさそう!x1)

Normalize

これを有効にすると、Force To Mono ミックスダウン処理中にオーディオは ノーマライズ されます。
結論:いつ(雑音で?)使われるんでしょう!!! 使ったことありません!(以降もなさそう!x2)

Load In Background

これを有効にすると、メインスレッドを妨げることなく、クリップの読み込みは別のスレッドで遅延させて行われます。
結論:CPU負荷分担したい時に使えそうです!

Ambisonic

アンビソニックオーディオソースは、リスナーの向きに基づいて回転する音場を表す形式でオーディオを格納します。全天球型のビデオや VR や AR アプリケーションに便利です。オーディオファイルにアンビソニックでエンコードされたオーディオが含まれている場合は、このオプションを有効にします。
結論:立体音声の時に使えそうです!

Preload Audio Data

オンになっている場合、シーンの読み込み時にオーディオクリップもあらかじめ読み込まれます。Unity の標準挙動ではシーンが再生される前にすべての AudioClip が完全に読み込まれるため、通常はオンになっています。このフラグが設定されていない場合、オーディオデータは、最初の AudioSource.Play()かAudioSource.PlayOneShot() か AudioSource.LoadAudioData() で読み込まれて AudioSource.UnloadAudioData() で再び破棄されます。
結論:マニュアル過ち修正 AudioSourceでなく、Audioclip.LoadAudioData()、Audioclip.UnloadAudioData()のはずです。
オン:端末が起動されシーンに入った時読み込まれますが、大量の音声データがある時、起動が遅くなるのが現象です。
オフ:起動負荷はないですが、音声Play()時読み込み解凍でcpu負荷がかかるのが現象でフレームが落ちます。なのでフレーム保持したいアプリとかは、事前に(初期化タイミング?)LoadAudioData()を呼び出しする必要があります。

LoadType

Decompress On Load

オーディオファイルは読み込まれるとすぐに展開されます。サイズの小さい圧縮サウンドにこのオプションを使えば、その場での展開に伴うパフォーマンスのオーバーヘッドを防ぐことができます。ただし、Vorbis でエンコードされたサウンドを読み込み時に展開すると、圧縮されたままの場合の10倍程(ADPCM エンコーディングでは約3.5倍)のメモリーを使用するので、サイズの大きいファイルにはこのオプションを使用しないでください。
結論:大体この設定でいいかもですが、大きいサイズは使えません!(大きいサイズ?これは個人の心の中の基準でしょうか!)

Compressed In Memory

サウンドはメモリ中では圧縮されたままで、再生中に展開されます。このオプションは若干のパフォーマンスオーバーヘッドが発生します(特に Ogg/Vorbis 圧縮ファイルの場合)ので、メモリー使用量が大きすぎて読み込み時に展開できないファイルにのみに使用してください。展開はミキサースレッドで行われ、Profiler ウィンドウ内の Audio ペインにある “DSP CPU” のセクションでモニタリングできます。
結論:音声play()時のcpuの負荷は小さくなるが、パッケージ(apk/ipa)した時のサイズが大量に大きくなります!お勧めしません!

Streaming

サウンドをその場でデコードします。この方式では、圧縮データのバッファーのための使用メモリーが最小限に抑えられます。データはディスクから段階的に読み込まれて必要に応じてデコードされます。展開は別のストリーミングスレッドで行われますが、その CPU 使用量は Pofiler ウィンドウ内の Audio ペインにある “Streaming CPU” のセクションでモニタリングできます。
結論:パッケージ(apk/ipa)した時のサイズがほぼない、cup負荷は分担され Decompress On Loadより小さい

Compression Format

PCM

品質は高くなりますが、ファイルサイズが大きくなります。非常に短い音響効果に最適です。
結論:説明の通りですが、使ったことありません!(以降もなさそう!x3)

ADPCM

この形式は、足音や衝突音、武器などのノイズを多く含んでいて大量に再生される必要があるサウンドに便利です。圧縮率は PCM の3.5分の1ですが、CPU の使用量は MP3/Vorbis 形式に比べ格段に少なくなるため、上記のような種類の音には適しています。
結論:雑音でNormalizeと一緒に使えそうですが、使ったことありません!(以降もなさそう!x4)

Vorbis/MP3

圧縮ファイルは小さくなりますが PCM オーディオに比べると若干クオリティが落ちます。圧縮率は Quality スライダーの調整で可能です。この形式は中程度の長さの SE や音楽に適しています。
結論:参考からAndroidはVorbis、iOSはMP3が最適のようです

Quality

圧縮 クリップに適用される圧縮の度合いを決定します。PCM/ADPCM/HEVAG 形式には適用されません。ファイルサイズに関する情報はインスペクターで確認できます。この値を調整する方法としては、スライダーをドラッグし、ファイルサイズを小さく保ったまま「許容できるレベルの」再生クオリティになるポイントを見つけるのがよいでしょう。(注)Original Size は元ファイルのサイズなので、例えばこれが MP3 ファイルで Compression Format が PCM (非圧縮)に設定されている場合、Ratio は結果として 100% を超える値になります。これは、ファイルが非圧縮で保存されるために元々のソースの MP3 ファイルよりも大きなスペースを取ってしまうからです。
結論:Ratioが100%を超えた時に手動で100%以下に抑えることができるハンドルでしょうか!

汎用まとめ

  • 大体の音源データロードタイプ
    • LoadType=Decompress On Load
  • 大きいすぎて展開できない音源データのみ
    • LoadType=Compressed In Memory
  • 長い音源データロードタイプ
    • LoadType=Streaming
  • 遅延で行われてもよく、cup負荷かけたくない時
    • Load In Background
  • 起動時にロードさせたいが、起動時間長くしたくない時
    • Preload Audio Data
    • Load In Background
  • Compression Format
    • Android : Vorbis
    • iOS : MP3

音声データインポートした時自動設定エディタ拡張

using UnityEngine;
using UnityEditor;

public class UnityAssetImporter : AssetPostprocessor
{
    /// <summary>
    /// 音源データインポートした後呼ばれる
    /// </summary>
    private void OnPostprocessAudio(AudioClip clip)
    {
        var audioimporter = (AudioImporter)assetImporter;
        audioimporter.Setting("iOS", AudioCompressionFormat.MP3, clip.length);
        audioimporter.Setting("Android", AudioCompressionFormat.Vorbis, clip.length);
        audioimporter.preloadAudioData = false;
    }
}
public static class ImpoterUtility
{
    public static void Setting(this AudioImporter importer, string platform, AudioCompressionFormat acformat, float length)
    {
        var setting = importer.GetOverrideSampleSettings(platform);
        setting.compressionFormat = acformat;
        //適当に時間でロードタイプ決める
        if (length >= 5f)
            setting.loadType = AudioClipLoadType.Streaming;
        else
            setting.loadType = AudioClipLoadType.DecompressOnLoad;
        importer.SetOverrideSampleSettings(platform, setting);
    }
}

注意
手動で設定変更した時拡張ファイルも一緒に一回実行されますので注意しましょう!

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

【デジタル署名】PlayStoreとAppStoreでAndroid・iOSアプリを配信する時の署名まわり【証明書】

「どうすればいいのか」という操作手順は探すと結構見つかるんですけど、

「それはなんのためにやるのか」というところがピンときてないと、

何かトラブった時に自分で対処できなかったり、

そもそも何をやってるかわからずに作業するのが気持ち悪かったりするので

それをなんとかする記事です。

間違いがあったらコメントで教えていただけるとありがたいです。他力本願…!

また、私自身で疑問が解決していないところは「ここがわからない?」という旨を随時書いていきます(?この絵文字で)ので、コメントで教えていただけるとありがたいです?。他力本願…!!

また、「デジタル署名」「公開鍵」「秘密鍵」「証明書」「認証局」などの言葉については既知とします。

知らなかったら先に調べてきてもらえると助かります。

…サラッと言ってますが、サクッと調べて2分で理解できるような概念ではないです。

ここで説明するとめちゃくちゃ長くなるので他に任せます、ということです。

そもそも何がしたいのか

両OSで共通してやりたいことは

配布するアプリにデジタル署名を施す

ということです。

デジタル署名が施してあれば、アプリを受け取る人は、手元にある「公開鍵(検証鍵)」を使って

  • アプリがその公開鍵と対応する秘密鍵を持つ人によって作られたこと
  • その秘密鍵で署名された後でアプリが改竄されていないこと

を確認できます。

なお、ユーザーはその公開鍵をいつ入手するかというと、

最初にそのアプリをインストールした時に一緒についてくる証明書に入ってる

ということになります。

署名で防げること(Android)

Androidの場合、署名の主な目的は「アプリを不正にアップデートされることを防ぐ」ことです。

こちらから引用します。(閲覧・引用日 2019年11月12日)
https://support.google.com/googleplay/android-developer/answer/7384423?hl=ja

Android アプリは秘密鍵で署名されます。アプリのアップデートが信頼できるものであることを保証するために、秘密鍵はそれぞれ公開鍵証明書に関連付けられています。デバイスやサービスはその公開鍵証明書を使って、アプリが信頼できる提供元によるものであることを確認できます。デバイスがアプリの更新を許可するのは、すでにそのデバイスにインストールされているアプリとアップデートで署名が一致する場合のみです。

既にインストールしたアプリと同じ製作者によるアップデートしか受け付けない、ということです。

この署名で防げないこと

Androidアプリには製作者の署名と、公開鍵証明書(公開鍵自体もそこに入っている)が含まれていますが

その「証明」を行ったのはアプリ制作者自身です。証明書に入っている公開鍵に対応する秘密鍵を使って、その公開鍵に署名したものです。

これを自己署名証明書と言います。

ということは、その公開鍵が正当な製作者のものであるという「第三者に依る保証」がありません。

攻撃者が偽アプリを作って、攻撃者自身が作った秘密鍵で署名し、自己署名証明書を同梱しても、受け取る人は正当な製作者によるものと区別がつきません。

なので、アップデート時以外、つまり、アプリを最初にデバイスにインストールする時(一度消して再びインストールする場合も含む)に、アプリそのものを署名や証明書ごとすり替えられる可能性が残ります。

ここは私もよくわかっていないところなのですが、

Play Storeとの通信がHTTPSで保護されている以上、そんな攻撃は考えられない、ということですかね??

Play Store以外から入手する場合は自己責任でいいと思いますけども。

署名で防げること(iOS)

iOSアプリの場合は、自己署名証明書ではなく、Appleが発行した証明書が付きます。

こちらのページから引用します。(閲覧・引用日 2019年11月12日)
https://developer.apple.com/jp/support/code-signing/

Appにコード署名をすると、そのAppが特定の発行元から提供されており、最後に署名した時点から改変されていないことをユーザーに保証できるようになります。MacやiOS Appを、ストアサービスで利用、開発やテスト用にiOSデバイスにインストール、App Storeに登録するには、Appleが発行した証明書で署名する必要があります。

アップデート時に限らず、最初のインストール時から、正当な製作者によるアプリであることが保証される、ということですね。

開発者からすると、Appleに公開鍵証明書をもらうという一手間が増えます。

「証明書で署名」?

…ところで。

私はこの引用に出てくる「証明書で署名」という表現が気になります。

これは「『証明書に含まれる公開鍵に対応する秘密鍵』で署名する」という意味に捉えればいいんですかね?

証明書に秘密鍵は含まれていませんから、「証明書で署名」と言われると「署名する時に証明書は関係ないじゃん」と思ってしまうんですが…?

共通の基本的な手順

ということで、デジタル署名を施してアプリをアップロードする大まかな手順は次のようになります。

  1. 秘密鍵・公開鍵のペアを作成する
  2. (Android)公開鍵の自己署名証明書を作る/(iOS)公開鍵をAppleに登録し、証明書をもらう
  3. 秘密鍵でアプリに署名し、証明書を同梱する
  4. アプリをストアにアップロード
  5. 秘密鍵と証明書のセットをどこかに保管しておく

となります。4と5はどっちが先でもいいです。

これがピンと来ていると、実際の作業も見通しが良くなります。

でもこれはあくまで基本的な流れで、具体的な流れはもっと細かくいろいろあります。

Androidの手順

ではもう少し具体的な流れを見てみましょう。

「何のソフトを開いて、どこをクリックして、何のコマンドを実行して…」というところまでは具体化しません。あくまで「この操作はこういうことをやっている」という解説です。

1. 2. 秘密鍵・公開鍵のペアを作り、自己署名証明書を作る

(アプリ開発が2つ目以降で、前回と同じ鍵を使う場合は、このステップは飛ばせます)

keytool --genkey (あと略)

このコマンドで、自己署名証明書の作成まで一度に行われます。

-genkeypair
(中略)
鍵のペア(公開鍵および関連する非公開鍵)を生成します。公開鍵はX.509 v3自己署名証明書でラップされます。

(https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/keytool.html より引用 2019年11月12日)

ちなみに多くの解説ではgenkeyとされているところは、現在(2019年11月12日)では

--genkeypair

を使うべきとされているようです。機能は同じ。

秘密鍵も、公開鍵を含んだ自己署名証明書もまとめて一つのkeystoreに保存されます。拡張子は.keystore.jksにすることが多いようです。

開発したアプリが2つ目以降の場合、前回と同じ鍵を使っても構いません。

3. アプリに署名し、証明書を同梱

いくつか方法があります。

  • zipalignapksigner
  • jarsignerzipalign
  • key.propertiesbuild.gradleを適切に書いてビルド時に自動で処理

と言ったところでしょうか。

zipalignは署名とは関係ない操作ですが、署名方法によってタイミングが変わってくるので書き足しておきました。

4. アップロード

Play Store Console からアプリの作成を行い、ビルドしたアプリ本体をアップロードします。

リリースするためには説明文を書いたり対象年齢を設定したりいろいろやることがありますがこの記事では割愛します。

5. 秘密鍵と証明書のセットを保管

先程作ったkeystoreファイルをどこかに保管すればOK。

「Google Play アプリ署名」を使う場合

GooglePlayアプリ署名を使う場合は、アプリ本体への署名をGoogleが代わりに行います。その際の鍵ペアと自己署名証明書はGoogleが勝手に作ります。

また、Play Storeにアップロードするものが、apkファイルではなくAndroid App Bundleになります。

(Android App Bundleではなくapkファイルをアップしつつ、「Google Play アプリ署名」を使用することもできるのかどうかはよくわかりません?)

ユーザーは、アプリの製作者が変わっていないことをGoogleが保証してくれるので、安心してアップデートできます。

あとは、製作者がアップデート版をアップロードする時に、Googleに対して「前と同じ製作者ですよ」ということを証明しないといけません。

なので結局、製作者も毎回署名をする必要があります。この時の署名に使う鍵は「アップロード鍵」と呼ばれます。

とはいえ署名手順はそこまで大きく変わりません。使った鍵がアップロード鍵と呼ばれるようになるだけです。

アップロード鍵も、複数のアプリで同じものを使用してもかまいません。

既にapkファイルをアップロードしたアプリを、 「Google Play アプリ署名」を使うように変更する場合

この場合、今後のアップデートでアプリに署名を施すのはGoogleになるわけですが、

ユーザー視点で考えると、アプリに施された署名はアップデート時も変わってはいけないので、

製作者は、これまで使っていたアプリ署名用の鍵をGoogleに渡し、使ってもらう必要があります。

つまりこれって秘密鍵を渡すことになります。

これは結構珍しい操作な気がしますがどうなんでしょう。

そして、今後自分が使うアップロード鍵を用意して、それもGoogleに伝えます。こちらは秘密鍵を渡してはいけません。公開鍵(を含んだ自己署名証明書)だけで十分ですね。

iOSの手順

続いてiOSです。こちらも「つまりどういうことをしているのか」の解説にとどめ、具体的な操作手順は解説しません。

実際の手順はこちらのサイトがわかりやすいです。
https://i-app-tec.com/ios/app-release.html

1. 秘密鍵・公開鍵のペアを作成する

今回は、いきなり「キーのペアを作る」という操作はしません。ではどうするのか。

この後のステップで、「Appleに証明書をお願いする」という部分があります。

一般的に、認証局に証明書をお願いする場合は「証明書署名要求(certificate signing request, CSR)」と呼ばれるものを作成し、それを認証局に送ります。

証明書署名要求(Wikipedia)

認証してもらえた場合、証明書が送り返されたり、ダウンロードできるようになる、という流れです。

iOSアプリを作る際は、お手元のMacに最初からインストールされているKeychainAccessというアプリケーションを使ってCSRを作成します。

Keychain Accessを使ってCSRを作成する際に、秘密鍵・公開鍵のペアも自動で作成されます。

事前に作っておく必要はないということです。

ステップが削減されるのは良いのですが、私ははじめ「鍵を作らずにCSRを作るってどういうことだ…」と混乱しました。

2. 公開鍵をAppleに登録し、証明書をもらう

Apple Developerにログインし、Certificatesの所から操作を行います。

その際に、先程作ったCSRを指定する行程があります。

これが完了すると、証明書がダウンロード可能になります。

実はダウンロードしなくてもXCodeからこの証明書を指定できるので、アプリをアップロードするためなら証明書はダウンロードしなくてかまいません。

が、後で秘密鍵とセットで保管するので、ダウンロードしておきましょう。その際、Keychain Accessに追加しておきます。

有効期限は1年

作った証明書の有効期限は1年ですから、切れる前に作り直す必要があります。

その場合はまたCSRの作成から行います。

署名に使う鍵も変更されるわけですね。この点はAndroidの場合と違いますね。アップデート時に製作者が変わっていないことを、「署名が変わっていないこと」ではなく、Appleの認証によって保証するわけですね。

作り直したら、Provisioning Profile(後述)を編集して、紐付ける証明書を切り替えておきましょう。

証明書はCSRを作ったMacに紐付いている

Macを買い替えたりした場合は紐付けをし直す必要があります。

やり方はここでは解説しないので調べてください?

3. 4. 秘密鍵でアプリに署名し、証明書を同梱し、アップロードする

Apple Developerでの作業

まずApple Developerのサイト上でApp IDの登録をします。

その後、Provisioning Profileというものを作ります。これもApple Developerのサイト上です。

Provisioning Profileは、次の3種類の情報の組み合わせを表したものです。

  • Certificate(証明書のこと)
  • App ID
  • テスト用端末のID

この情報があることで、Appleは「どのアプリとどの証明書をくっつけて配信すればいいのか」を把握できます。

Certificate(証明書)の有効期限が1年で切れますので、その前に新しい証明書を作って紐付けておきましょう。

ちなみに、Provisioning ProfileとApp IDの紐付けは一対一対応ではないそうです。どういうケースで一対一対応ではなくなるのかコレガワカラナイ?

XCodeでの作業

アプリのプログラムそのものは、XCodeを使ってアップロードします。

その際に、先程作ったProvisioning Profileを指定します。そこに証明書の情報も紐付いているので、先程作った証明書を使ってくれるようになります。

もろもろ調整してアップロードします。

余談ですが、この部分でかなりいろんなエラーに悩まされると思います。私は「アイコンに透明度が設定されている」というエラーが一番多かったです。その場合は透明度を抜いた画像を作り直して設定し直します。

App Store Connectでの作業

最後にApp Store Connectのサイト上で、新しいアプリを登録し、スクリーンショットや説明文など必要な情報を登録します。先程作ったApp IDとの紐付けも行います。

Androidで言うところの、Play Store Console上での作業に相当します。

5. 秘密鍵と証明書のセットを保管

Keychain Accessをまた開いて、先程ダウンロードした証明書と、それに対応した秘密鍵をセットにしたp12ファイルというものを作成できます。それを保管すればOK。

CategoryはMy Certificateを選んでおかないと、p12を選択できませんので注意。

Keychain AccessをまるごとiCloudで管理しておくという手もありますね。

おわり

この記事は以上です。

署名まわりの話はややこしいですが、この記事の内容を理解しておけば、何が何だかわからずに作業するよりもずっと見通しが良くなると思います。

もし間違いがありましたら教えていただけると幸いです。また、疑問点として残した所もご存知の方がおられましたら教えていただけると幸いです。他力本願…!!!

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