AFNetworkingのリクエストでCookieを扱う方法

先月はSwiftをやっていましたが,今月はObjective-Cです.
数年ぶりに他人が書いたObjective-CでAFNetworkingライブラリを使用した通信処理を読んでいて,Cookieを扱う処理がわからず困ったのでメモしておきます.

▼ AFNetwork でリクエストにCookieを設定する

リクエスト ヘッダにクッキーを設定するには以下のように記述します.

NSString *cookie = [NSString stringWithFormat: @"(Cookieのキー名)=%@; path=/; HttpOnly", (設定する値)];    
[manager.requestSerializer setValue: cookie forHTTPHeaderField: @"Cookie"];        

▼ リクエスト ヘッダを参照する

正しくリクエスト ヘッダにクッキーが設定されているかは,デバッグウィンドウで以下のように参照できます.

(lldb) po manager.requestSerializer.HTTPRequestHeaders

▼ レスポンス ヘッダを参照する

レスポンス ヘッダを参照するには以下のようにレスポンスを受信時に参照できます.

コード省略
	:
success:^(NSURLSessionTask *operation, id responseObject){    
NSHTTPURLResponse *response = (NSHTTPURLResponse *)[operation response];    
 
(lldb) po response.allHeaderFields

▼ レスポンス ヘッダで参照できなかったCookieをCookieストレージで参照する

今回少し困ったことに以下のようにしてもレスポンス ヘッダで参照できるクッキーが参照できなかったので、記事を参考にCookieストレージから参照することで対処しました.

NSString *cookie = httpUrlResponse.allHeaderFields[@"Set-Cookie"];

スタックオーバーフローに参考になる記事がありましたので,メモしておきます.

(参考)How to use AFNetworking to save cookies permanently forever, until the app is deleted from the iPhone?

以下,参考になると思われる部分を抜粋です.

1) Upon successful authentication, the webservice hands me two cookies. 
How do I access them? Do I go straight to NSHTTPCookie storage and grab the cookie by its name, or is there an AFNetworking "way" to do this?

AFNetworking doesn't do anything explicitly with cookies so there is no "AFNetworking way" of dealing with cookies. 
You'll work with NSHTTPCookie and NSHTTPCookieStorage.

【Google翻訳】
1)認証に成功すると、Webサービスは2つのCookieを渡します。それらにアクセスするにはどうすればよいですか? 
NSHTTPCookieストレージに直接移動して、名前でCookieを取得しますか、それともAFNetworkingの「方法」がありますか?

AFNetworkingはCookieを明示的に処理しないため、Cookieを処理する「AFNetworkingの方法」はありません。 
NSHTTPCookieとNSHTTPCookieStorageを使用します。

NSURLSessionでCookieを扱うサンプルは以下が参考になります.
(参考)iOS7:NSURLSessionのhttp(cookie)でハマった

Objective-Cで書かれた通信処理のサンプルを探していて困ったのは,以下のクラスの関係です.
それぞれバージョンアップで改変されたクラスであると理解して情報を参照した方が理解しやすいと思います.

AFHTTPOperationManager → AFHTTPSessionManager
NSURLSession → NSURLConnection

UIActivityViewController の使用方法について

先日,LINEで送る機能を実装したのが,UIActivityViewController を使用する際に iOS仕様で悩んだ点があったので,メモしておく.

従来よりアプリに「LINEで送る」機能を実装する場合,line://msg/ といった URLをオープンすることで LINE アプリを起動してメッセージを送信する手法を利用していたのだが,今回は UIActivityViewController を使用してみた.

まず,UIActivityViewController についてよく分からなかったのが,上段/下段がどのようなルールで分けられているのか?という点.

調べてみると iOS としては,Share (Share Extension) / Action (Activity) で分けたいようだ.
(サンプルとしてみた資料に上段,下段ともに Evernote の色つきアイコンと白黒アイコンが並んでいる様子をみて,最初意味が分からなかった.それぞれのアイコンでどこが違うの?)

これは,少し分かりづらい仕様だと思います.
(実際には,下段に表示される Activity でもプロパティー設定により,上段で表示することが可能.)

UIActivityViewController
これらを把握しておけば,簡単に実装できます.

Acitivity を理解したければ,以下のライブラリのコードをざっとみれば確認できます.

以下,調べた事柄をメモしておきます.

▼ iOS アプリから「LINEで送る」には?

LINE 公式
https://media.line.me/ja/

▼ iOS「LINE で送信」を行えるライブラリ

LineActivity
https://github.com/OopsMouse/LINEActivity

LineKit
https://github.com/dlackty/LineKit

▼ UIActivityViewController を使用する方法

上記のライブラリを使用して,UIActivityViewController に LINE のアクティビティを表示するには,以下のようにする.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NSArray *activities = @[[[LINEActivity alloc] init]];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[shareText]
                                                                         	applicationActivities:activities];
// 使用しないアクティビティタイプ
NSArray *excludedActivityTypes = @[ UIActivityTypePostToWeibo,
                                    UIActivityTypeSaveToCameraRoll,
                                    UIActivityTypePrint,
                                    UIActivityTypeCopyToPasteboard,
                                    UIActivityTypeAirDrop,
                                    UIActivityTypeAssignToContact,
                                    UIActivityTypeAddToReadingList,
				    UIActivityTypeMail,
                                    UIActivityTypeMessage ];
activityVC.excludedActivityTypes = excludedActivityTypes;
[self presentViewController:activityVC animated:YES completion:NULL];

– iOS 7からUIAcitivityが上段と下段に分かれたデザインが採用されている.
+ (UIActivityCategory)activityCategory に以下の値を指定することで表示位置が指定できる.
上段: UIActivityCategoryShare
下段: UIActivityCategoryAction

▼ 注意点

– URLスキームがiOS9から使用方法が変更されている点
・iOS9から従来のopenURLメソッドを実行するだけでは,カスタムURLスキームが使用できなくなっている.

・カスタムURLスキームを使用するには,Info.plist に以下の設定を追加する.
custom_url_scheme は,「://」が必要ないことに注意.

1
2
3
4
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>custom_url_scheme</string>
</array>

SQLite を C/C++ のインタフェースでアクセスする方法

2016年現在では,iOS アプリでローカルのデータベースへアクセスする手法はライブラリを使用する方法が主流だと思います.
Magical Record,新しいデータベースとしては,Realm (レルム)とかでしょうか.

ですが,過去に作成されたアプリの回収など,C/C++ のインターフェースを用いたアクセスを行っているアプリを改修する機会もあるかと思います.

今回そのような機会があったので,簡単に概要を把握できる資料を探してみました.
以下に簡単に記しておきます.

【cocos2d-x】sqlite3のドキュメントを訳してみた

C インタフェースの説明が記されています.
これらのインタフェースを把握するだけで,とりあえず SQL文の発行ができるので,事足ります.

SQLiteの基本的な使い方

サンプルソースが記されています.
上記で把握したインタフェースの使用方法が理解できます.
とりあえずこれだけ読めば,10分程度で SQLite に SQL文が使用できるようになります.

Swift で Objective-C のカテゴリを実装する方法

既存の Objective-C のコードを Swift 化していて Objective-C のカテゴリって Swift でどうするの?と調べてみると以下のような見解が紹介されていました.

Swiftで継承とカテゴリってどうやってやるの!?

Swift で UIView を角丸にするカテゴリ メソッドを追加するには,以下のように記述すれば実装できるようです.

1
2
3
4
5
6
7
extension UIView {
    // 角丸にする.
    func cornerRadiusClippedToBounds() {
        self.layer.cornerRadius = 5
        self.clipsToBounds = true
    }
}

では,上記のコードのファイル名はどうすべきなのか?というのは… 結局,Objective-C と同じ流儀が紹介されていました.

Swift で Extension につけるファイル名のベストプラクティス

Swift と Objective-C との連携方法

Objective-C で定義したクラスを Swift で使用する

【ブリッジヘッダーファイルを追加する】

ブリッジヘッダーファイルは,$(TARGET_NAME)-Bridging-Header.h で,プロジェクトに追加する.

Swift で利用する Objective-C クラスをブリッジヘッダーファイルに記載する.

【Build Settings ー Objective-C Bridging Header を設定する】
ブリッジヘッダーファイルが Swift に取り込まれるように、ターゲット – Build Settings 設定に登録する.

Swift Compiler - Code Generation
Objective-C Bridging Header
$(TARGET_NAME)/$(TARGET_NAME)-Bridging-Header.h と指定する.

【Swift で Objective-C クラスの呼び出し方】
Objective-Cのインスタンスメソッドの場合、 “textWithString:” のようなメソッドは “textWithString(str)” と呼び出す.
“textWithString: string:” というメソッドの場合, “textWithString(str1, string:str2)” と呼び出す.

Swift にインポートした Objective-C クラスは、そのまま継承して新しい Swift クラスを定義できる.

Swift で定義したクラスを Objective-C で使用する

【Swift クラスが定義されたヘッダーファイルをインポートする】
Swift で定義したクラスを利用するには、それを使用したい実装ファイル内に、次のように #import 文を記載する.

#import "$(PROJECT_NAME)-Swift.h

このファイルは、プロジェクト自体には登録されていないが、Derived Data の中間ファイルとして “DerivedSources” フォルダーに自動的に生成されている.