Akata Works

東京エンジニア。主にRuby,Go,たまにAWSとiOS。ゲーム音楽が好きです。連絡はTwitterかakata.onen@gmail.comまで

Deployment TargetとBase SDKと互換性について

XcodeのDeployment TargetとBase SDKがややこしかったのでまとめてみました。なるべくわかりやすく書いたつもりです。「間違っているぞー」とい点があればご指摘いただけると幸いです。

前提

そもそもの話として、Appleは各種OS(Mac OSiOS)とそのバージョンごとに異なるSDKを用意しており、それぞれの端末には対応するSDKが事前に組み込まれています。これにより以下のようなメリットがあります。

  • 同一実行ファイルでありながら、機能が組み込まれていればそれを活用し、組み込まれていくてもそれなりに対処できる
  • Base SDKからある程度の上位・下位バージョンへの互換性が担保できる

で、この「組み込まれているか、組み込まれていないか」を判断する必要があるSDKの範囲を決めるのがDeployment TargetとBase SDKです。

Deployment Target(配布ターゲット)

開発者がソフトウェアの動作を保証する最も古いSDKのバージョンを表します。つまり、これ以上のSDK上では動作を保証する必要があるけど、これより古いSDK上ではクラッシュしても知りませんってことです。

動作を保証する必要がないため、これ以下のバージョンで実装された機能にはがっつりと強リンク(機能がなければクラッシュする)が張られます。

Base SDK

ソフトウェアのコンパイル時に基準とするSDKのバージョンを表します。つまり、これより新しいSDK上で定義された機能は使えません(コンパイルエラー)。

また、このバージョンで廃止予定とされている機能はこれ以降のバージョンでは存在しない可能性があるためさっさと移行したほうがいいです。多分警告が出ると思います。

廃止予定の機能さえ使用していなければ上位互換性はほぼ保証されます。なぜなら、コンパイル時により新しいSDKで定義された機能は使ってないし、廃止予定でない機能が急に消されることはない(はず)だからです。

Deployment Target〜Base SDK

前項までで、Deployment Target以前の機能は気にする必要がないので無視して問題がないこと、Base SDK以上の機能は廃止予定のものを使っていなければほぼ安全であるということがわかりました。

ただ、これらのバージョン間で実装(変更)された機能に関してはユーザの端末に定義されているとは限りません。メソッドが追加されたり、挙動が変更されたりといろいろ考えられます。

故に、これらの機能にはソースコード上で動的に変更が可能なように弱リンク(機能がなければヌルポになる)が張られ、機能が定義されているか事前に確認する必要があります。

具体的な実装方法に関しては省きますが、参考URLにあるAppleの公式ドキュメントが一番まとまっていると思います。

まとめ

まとめると、このあたりをきちんと守っていれば互換性に関しては問題ないと思います。

f:id:akatakun:20180614194429p:plain (参考URL: Appleの公式ドキュメントから)

  • Deployment Target以前: 動作を保証をしない
  • Deployment Target以上〜Base SDK以下: 動作を保証する。追加・変更された機能はフレームワーク読み込み設定やソースコードで順応させる必要がある
  • Base SDK以降: 動作を保証する。廃止予定の機能は極力使わない

おわり。

参考URL

https://developer.apple.com/jp/documentation/cross_development.pdf

Twitter OAuthが403 Forbiddenを返すようになったので対応した

2018/06/13夕方頃からコードを変更していないのに急にTwitter OAuth APIが403 Forbiddenを返すようになりました。Twitterにて同じような報告を確認し、調べてみたところ、結構前から言われてたみたいですが、いやー気づかなかったっすね(^ ^ ;)

コールバックロックを有効にしていなくてもCallback URLsに設定済みのcallback_urlパラメータ以外はエラー返すよってことらしいです。変更理由としてはセキュリティのためとか。Enable Callback Lockingの設定項目はそのうち消えるらしいです。

対応策

対応は簡単で、https://apps.twitter.com/のアプリSettingsのCallback URLsに認証時に使うcallback_urlパラメータを設定してやればいいです。

f:id:akatakun:20180614115540p:plain

ちなみに、最低二つ以上設定する必要があります(ちょっと理由はわからなかったです)

f:id:akatakun:20180614115413p:plain

(はじめは出なかったが一度Callback URLsを二つ指定してからはこのエラーが出るようにりました)

また開発環境でテストする際、localhostのCallback URLは指定できませんが、127.0.0.1は指定できます。同様にhttp://localhost:3000でアクセスしたら403エラーが返ってくるのでhttp://127.0.0.1:3000でアクセスする必要があります。


いろいろ見てると「できない」という声が結構ありましたが、僕の場合はこれでいけたのでご参考になれば幸いです。

補足

ワイルドカードは使えない

Callback URLsにはワイルドカードが使えないっぽいので、動的URLを指定することはできないです。その場合は下記みたいにCallback用のページを用意してCookieとか使ってリダイレクトさせればいいんじゃないでしょうか。

なんでワイルドカード指定できねえんだよっ!調べたらちゃんと理由ありました。

参考

CocoaPodsクイックリメンバー用【ほぼメモ】

About CocoaPods

iOSのライブラリ管理ツール。他言語のツールだとBundler(Ruby)とかYarn(JS)とかが近い

How to Start

Rubyで動作するためGemからインストール

gem install cocoapods

Podfileを作成

pod setup

Commands

Podfile.lock > Podfileの優先順位でライブラリを追加(更新)。lockを見るので追加済みのものはバージョン固定。ライブラリ追加時はこれ

pod install

Podfileでライブラリを追加(更新)。lockを見ないのでバージョン変動。アップデート時はこれ

pod update ${lib_name} # 特定のライブラリに限定
pod update # 怖い

インストールバージョンと最新バージョンを調べる。updateしても最新バージョンにならないときは大体Podfileのplatform制限のせい

pod outdated

Podfile

platform :ios, '8'

target :testTests do
  pod 'Kiwi', '>=2.3.0' # Bug Fix https://github.com/kiwi-bdd/Kiwi/pull/542
  pod 'OCMock'
end

target: ライブラリをビルドする際のDeployment target(最低SDK Version)とかアーキテクチャを指定

Base64エンコードとBase64URLエンコードについて

GoogleさんのProtocol Buffersでエンコードしたデータをクエリパラメータで含めようと思ったので改めてBase64エンコードとBase64URLエンコードについて調べてみました

Base64エンコーディングについては以下の記事でも軽く触っていますが、データを印字可能な64種類のデータで表現するエンコード方式です
よくマルチバイト文字やバイナリデータをポストするのに使っているイメージがします

ただ、URLの一部として利用する場合は62 indexの+と63 indexの/,パディングの=がURLセーフではない(RFC3986とapplication/x-www-form-urlencoded)ため、
URLセーフにエンコードするべきです
パーセントエンコーディングはデカいしキモいのでなるべく避けたいっすね

Base64URL Encoding

+-に、/_に変更するのが仕様みたいです。パディングは省略されます

RFC 4648 - The Base16, Base32, and Base64 Data Encodings

このようにBase64の中でもこのようにURLセーフなものをBase64URLと区別します

Ruby

RubyではBase64.#urlsafe_encode64にて提供されますが、内部的にはRFC4648で変換した後、後から+/を置換します

https://apidock.com/ruby/Base64/urlsafe_encode64

def urlsafe_encode64(bin)
  strict_encode64(bin).tr("+/", "-_")
end

Go

Goではbase64.RawURLEncodingにて提供されます。Paddingを含むbase64.URLEncodingもあります
Rubyとは違って置換ではなくはcharsetが予めURLセーフになっている点が無駄がないですね

const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

// ...

var RawURLEncoding = URLEncoding.WithPadding(NoPadding)

MongoDB TTLのexpireAfterSecondsを変更する

MongoDBにはドキュメントサイズで削除するキャップ付きコレクションと有効期限で削除するTTLインデックスがあります

TTLインデックスの有効期限であるexpireAfterSecondsを変更する方法には二種類あり、dropIndexからのcreateIndexでインデックスを張り直すというのも一つの手ですが、backgroundオプションがなければロックがかかりますし、あってもbackgroundオプションありで作られたインデックスは最適化されるまで時間がかかります

なので、runCommandとcollModを使った方法をおすすめします

db.runCommand({collMod: <collection_name>, index: {keyPattern: <key_pattern>, expireAfterSeconds: <expire_after_seconds>}})
db.runCommand({collMod: 'example_colls', index: {keyPattern: {datetime: 1}, expireAfterSeconds: 86400}})

らくちん

参考URL

Expire Data from Collections by Setting TTL — MongoDB Manual 3.4

Bitcodeバージョンの違いで発生するInvalid bitcode version (Producer: xxxx Reader: yyyy)

タイトルイコールほぼ答えみたいなものですが、Facebook SDKなど外部のフレームワークを使用する場合、SDKをビルドした際のBitcodeバージョンとそれを使用したアプリをビルドした際のBitcodeバージョンが異なればアーカイブ時にタイトルのエラー
が出ます(xxxxとyyyyはBitcodeのバージョン)

Bitcodeについては下記の過去記事で解説しています。よく分からない人はどうぞ


対応策としてはTARGETSの設定からBuild Settings => Build Options => Enable BitcodeをNoにすることでBitcodeを無効にすることで解消できますが、
Bitcodeをオフにすることで何らかの問題が発生する可能性がないとは言い切れませんし、最適化のためにあまりよくありません

基本的に新しい外部SDKはその時の最新のXcodeでビルドされていると思いますので、Xcodeコードのバージョンを上げるのが一番いいと思います
どうしてもXcodeのバージョン上げたくなければ古いSDKを使用するか、
設定でオフにするといいんじゃないでしょうか

XcodeバージョンとBitcodeバージョンの対応表どっかにないかな・・

僕が引っかかったときのBitcodeバージョンは以下でした

Xcode 8.3.3: 802.0.42.0_0
Xcode 8.2.1: 800.0.42.1_0

参考URL

Rails Console(irb)のアウトプット待ちがメンドイときに消す方法

小ネタです。Rails Console(irb)で適当な処理を実行すると返却値が出力されますよね?例えば以下のeachメソッドの返却値はレシーバ自身なので、eachブロックでゴニョゴニョ処理をするとレシーバが出力されます

> %w/hoge huga foo bar/.each{|e| e}
=> ["hoge", "huga", "foo", "bar"]

ちょっとした実行なら便利です


が、たまにステージングエリアのRails Consoleで大量のリソースをeachブロックで処理をする時とかに、これが少し邪魔になることになります

> Resource.where(statements).each{|record| record}
  Resource Load ...
=> [#<Resource id: 1, hoge: "aaaa", huga: "bbbb", foo: "cccc", bar: "dddd">, ...(以下略

返却値のActiveRecord::Relationオブジェクトが小さければいいですが、大きいと出力に時間がかかりますし、過去の情報が流れてしまいます

解決策

irbの出力は最後に実行された文の返却値みたいなので単純に; 0を追加すればかなりさっぱりします

> Resource.where(statements).each{|record| record}; 0
  Resource Load ...
=> 0

あースッキリした

参考URL