はじめに
iOS 11 になって Twitter や Facebook への投稿や API にアクセスするために利用していた Account.framework と Social.framework が使えなくなった。 Apple は、 Twitter と Facebook が提供している公式の SDK の利用をを推奨している。これらを使うのが正しい方法なのだろう。でも、その際の既存のソースコードの修正がとても面倒臭い。
そのため、iOS 10.3 までのソースコードを可能なかぎり少ない修正で、かつ Account.framework と Social.framework の代替ができる SocialAccountKitSwift を作成した。 このフレームワークを使用すれば、従来とほぼ同じような感じで Twitter や Facebook の API にアクセスできる。
何ができるの
以下のような iOS 10.3 までの Social.framework を使った Twitter に投稿するソースコードが、
if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeTwitter) {
if let slc = SLComposeViewController(forServiceType: SLServiceTypeTwitter) {
slc.completionHandler = {
(result: SLComposeViewControllerResult) -> Void in
switch (result) {
case .done:
print("tweeted")
case .cancelled:
print("tweet cancel")
}
}
present(slc, animated: true, completion: nil)
}
}
次のように書き換えられる。 修正箇所が少なくって、とても楽チン。
let accountType = SAKAccountType(.twitter)
if SAKComposeViewController.isAvailable(for: accountType) {
if let slc = SAKComposeViewController(for: accountType) {
slc.completionHandler = {
(result: SAKComposeViewControllerResult) -> Void in
switch (result) {
case .done(let json): // API の Response を JSON 形式で受け取れる
print("tweeted")
case .cancelled:
print("tweet cancel")
case .error(let error): // Error も受け取れる
print(error.localizedDescription)
}
}
present(slc, animated: true, completion: nil)
}
}
同様に、 Twitter の API にアクセスするコードは、
let requestURL = URL(string: "https://api.twitter.com/1.1/statuses/home_timeline.json")!
if let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, url: requestURL, parameters: [:]) {
request.account = self.account
request.perform(handler: { (responseData, urlResponse, error) in
if let jsonData = responseData {
dump(jsonData)
}
})
}
以下のように書き換え可能である。
let requestURL = URL(string: "https://api.twitter.com/1.1/statuses/home_timeline.json")!
if let request = try? SAKRequest(forAccount: self.account, requestMethod: .GET, url: requestURL, parameters: [:]) {
request.perform(handler: { (responseData, urlResponse, error) in
if let jsonData = responseData {
dump(jsonData)
}
})
}
ざっくり説明すると、 AC と SL 接頭辞で始まるコードが SAK 接頭辞に置き換わっただけ。ACAccount も SAKAccount になった。開発者が自分でアカウント管理の仕組みを実装しない限り、大きな手間はないと思う。
SocialAccountKit の使い方
自作アプリに組み込むまでの手順を説明するよ。
ほとんどが OAuth 認証のための準備に費すんだけどね。
SocialAccountKitSwift.framework の作成
- GitHub にアクセスして、ソースコードを clone するか zip 形式でダウンロードする。
- Xcode で Project を開き、Target を SocialAccountKitSwiftFatBinary を選択し、 Build を実行する。
- SocialAccountKitSwift.framework が作成されたフォルダが表示されるので、${HOME}/Library/Frameworks などにコピーする。
API Key と API Secret の入手と設定
アカウント管理のために、Twitter と Facebook から API Key と API Secret を入手する必要がある。どちらか一方しか利用しないなら、必要なサービスの API Key と API Secret を取得すれば良い。
Twitter を使う場合
- Twitter Application Management ページにアクセスする。
- Create New App を実行して、アプリケーションを登録する。
- Keys and Access Tokens タブを選択し、 Consumer Key と Consumer Secret の文字列をコピーする。
- Xcode Project 内の Twitter.plist の CosumerKey と ConsumerSecret にペーストする。
<plist version="1.0">
<dict>
<key>ConsumerKey</key>
<string>YOUR CONSUMER KEY</string>
<key>ConsumerSecret</key>
<string>YOUR CONSUMER SECRET</string>
</dict>
</plist>
Facebook を使う場合
- 開発者向け Facebook ページにアクセスする。
- 右上の マイアプリ から 新しいアプリを追加 を選択し、アプリを登録する。
- ダッシュボード画面の アプリID と app secret の文字列をコピーする。
- Xcode Project 内の Facebook.plist の AppID と AppSecret にペーストする。
<plist version="1.0">
<dict>
<key>AppID</key>
<string>YOUR APP ID</string>
<key>AppSecret</key>
<string>YOUR APP SECRET</string>
<key>Permissions</key>
<array>
<string>public_profile</string>
<string>email</string>
<string>manage_pages</string>
<string>publish_pages</string>
<string>publish_actions</string>
<string>user_posts</string>
<string>user_friends</string>
</array>
</dict>
</plist>
Permissions の値を調整したい場合は、アクセス許可のリファレンス - Facebook >ログイン を参照してね。
Permission の値は認証後に変更できないので気を付けよう。また、 Facebook の承認が必要な値もあるので注意しよう。
さらにもう一手間、 OAuth 認証の設定をするよ。
- プロダクト画面で Facebook ログイン を追加する。
- クライアントOAuth設定 画面を開く。
- クライアントOAuthログイン と 埋め込みブラウザOAuthログイン を はい に変更する。
Facebook の設定は、いろいろと複雑なので、先ずは OAuth 認証でアカウント作成ができるかどうかを確認してから、プログラムの開発を進めると良い。
API Key と API Secret の確認
取得した API Key と API Secret を使って SocialAccountKitDemo を実行してアカウント登録してみよう。
- Twitter.plist あるいは Facebook.plist に入手した API Key と API Secret を設定する。
- Xcode の Target を SocialAccountKitDemo に変更して Run を実行する。
- アプリが起動したなら、画面右上の + ボタンをタップする。
- アカウント管理画面に切り替わるので、右上の Edit ボタンをタップする。
- Add New Account をタップする。
- Twitter / Facebook の認証画面に切り替わるので、 ID とパスワードを入力する。
- 認証が無事完了したら、アカウント管理画面に戻るので、右上の Done ボタンをタップする。
- 左上の × ボタンをタップしてアカウント画面を閉じる。
上記一連の操作でエラーが起きなければ、取得した API Key と API Secret が正しく使えるのが確認できた。
それと、デモアプリの左上のボタンをタップすると、登録したアカウントの一覧が表示される。選択すれば、タイムラインの情報を画面に表示するよ。また、画面左下のボタンをタップすると、投稿画面が表示されるので、自分のタイムラインに文章を書き込めるよ。試してみてね。
自作アプリに組み込む
Xcode での設定
Embedded Binaries に作成した SocialAccountKitSwift.framework を登録する。
アカウント管理機能の実装(必須)
iOS 10.3 までは、 iOS の 設定 アプリ内で Twitter と Facebook のアカウント管理機能が提供されていた。 iOS 11 以降では、それらの機能が削除されている。そのため、アプリ毎にアカウントを管理する必要がある。
このアカウント管理の仕組みを提供するのが、 SAKAccountViewController クラスである。 そのため、SocialAccountKitSwift を利用するなら、必ずこのクラスを呼び出す仕組みを実装しなければならない。
たとえば、UIBarButtonItem から Twitter のアカウント管理画面を呼び出すには、以下のようなコードを実装する。
func manageAction(_ sender: UIBarButtonItem) {
let accountType = SAKAccountType(.twitter)
let viewController = SAKAccountViewController(accountType: accountType)
present(viewController, animated: true, completion: nil)
}
SAKAccountViewController クラスは、アカウントの登録と削除のみの機能を提供する。もし独自のアカウント管理画面を実装したいなら、 SocialAccountKit フォルダ内の AccountViewController.swift を参考にすると良い。
アカウントの取得
登録したアカウント情報は次のようなコードで取得できる。 例は Twitter の場合。
class MyClass
{
let store = SAKAccountStore.shared
var accounts = [SAKAccount]()
func getAccounts() {
let accountType = SAKAccountType(.twitter)
store.requestAccessToAccounts(with: accountType, completion: {
[unowned self] (granted: Bool, error: Error?) in
guard granted, error == nil else { return }
if let accounts = self.store.accounts(with: self.accountType) {
self.accounts = accounts
}
})
}
}
上記のコードでも分かるように、可能なかぎり従来の Account.framework からの修正を少なくなるようにしている。この場合は、ACAccountStore に対応する SAKAccountStore である。違いは、 SAKAccountStore は Singleton なだけ。
それと、requestAccessToAccounts() の第一引数が、SAKAccountType になった点かな。
API へのアクセス
iOS 10.3 までは、Social.framework の SLRequest クラスを利用すれば、Twitter や Facebook の API にアクセスできた。同様に、SocialAccountKitSwift でも SAKRequest クラスとして機能を提供している。
以下のコードでは、Twitter のタイムライン上の情報を 20件取得する。 エラー処理は省略。
let account: SAKAccount = self.accounts.first!
let accountType = SAKAccountType(.twitter)
let requestURL = URL(string: "https://api.twitter.com/1.1/statuses/home_timeline.json")!
let parameters: [String:Any] = [
"count" : 20
]
let request = try? SAKRequest(forAccount: account, requestMethod: .GET, url: requestURL, parameters: parameters)
request.perform(handler: {
[unowned self] (data, response, error) in
guard error == nil, let data = data else { return }
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [Dictionary<String,Any>]
dump(json)
}
})
SLRequest() と SAKRequest() の違いは、第一引数に SAKAccount を取っている所である。また、例外を投げるのも異なる。この点に関しては、エラー処理の設計がイマイチなのが原因である。
これらについて注意すれば、既存のソースコードのちょっとした修正で、iOS 11 でも API へのアクセスが可能になる。
タイムラインへの投稿
Twitter や Facebook のタイムラインへの投稿も、 SAKComposeViewController クラスを利用して可能である。これも、SLComposeViewController クラスとほぼ同じ使い方である。違いは、第一引数に、SAKAccountType を渡す点である。この点に気を付ければ、従来のソースコードの修正も簡単に実施できるだろう。
func composeAction(_ sender: UIBarButtonItem) {
let accountType = SAKAccountType(.twitter)
if SAKComposeViewController.isAvailable(for: accountType) {
let viewController = SAKComposeViewController(for: accountType)
viewController.completionHandler = {
[unowned self] (result: SAKComposeViewControllerResult) -> Void in
switch result {
case .cancelled:
print("cancelled")
case .done(let json): // XXX: 'json' may be 'nil'.
dump(json)
case .error(let error):
print(error.localizedDescription)
}
}
present(viewController, animated: true, completion: nil)
}
}
ダウンロード
Xcode Project 一式 は、 github から入手可能。
スクリーンショットもあるので、そちらも参考にしてね。
おわりに
SocialAccountKitSwift は、 iOS 10.3 までの Account.framework と Social.framework を使ったソースコードをできるだけ少ない手間で iOS 11 以降でも動作させるためのフレームワークだ。手間を惜しまないのであれば、 Twitter と Facebook が提供している公式の SDK を利用して対応するのが正解なのだろう。
私は、Account.framework と Social.framework を既存のアプリで結構使っているので、そのためだけに 公式 SDK を使って対応するのが面倒だと思った。なので、SocialAccountKitSwift を作ったのだ。 自作フレームワークを作るまでは大変だが、作った後の対応は段違いに楽だ。
それと、このフレームワークを使う利点は、困ったらソースコードを見て自分で改良できるところだろう。 OAuth 認証のコードも RFC 5849 を読んで実装したので、自作アプリで使う際の参考にもなるだろう。他のサービスへの対応も考慮した設計にしたつもりだが、どうだろうか。