2012年2月10日金曜日

iOS アプリからのSOAP/WebServiceへのアクセス


iOSアプリからDOT.NETで作成したWebServiceにアクセスしようとしたところ、iOS SDKにはSOAPのサポートがありません。WebObjectsには含まれているようです。
Wei-Meng Lee氏のブログを見つけ、それを参考に実装してみました。
Consuming XML Web Services in iPhone Applications
日本語版もあります。
iPhoneアプリケーションでXML Webサービスを利用する

対象バージョンがちょっと古いためXcode4.2では若干の読み替えの必要はあります。
  • ARCではreleaseが使えないと警告が出るので削除する。(またはbuildオプション-fno-objc-arcを使う。)
  • サンプルで使用されているWebServiceがなくなっている。
    http://www.ecubicle.net/iptocountry.asmx
    自開発のWebServiceを対象にするならそれを使えばよいし、試していませんがiptocountryに類似のサイトもあります。
    WSIP2Country
SOAP 1.1と1.2でヘッダ情報が異なりますが、このSampleの範囲ではどちらでも結果は同じです。
サンプルのiptocountryは1.1の形式になっているので、コードをコピペするときはバージョンが混在しないように気を付けましょう。

SOAPヘッダの相違点:

SOAP 1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.ecubicle.net/webservices/FindCountryAsXml"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

SOAP 1.2
Content-Type: application/soap+xml; charset=utf-8
SOAPActionなし
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"

参考:たのしいXML: SOAP入門 6. SOAP 1.1 と SOAP 1.2 の違い

コーディングサンプル

    //SOAPメッセージ組み立て
    NSString *method = @"DoSomethins";
    NSString *namespace = @"http://myNameSpace/";
    NSString *paramStr = "<paramStr>abc</paramStr>";
    NSString *paramInt = "<paramInt>123</paramInt>";

    NSString *soapMsg = [NSString stringWithFormat:
                         @"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
                         "<soap:Envelope "
                         //"xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" "
                         "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                         "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
                         "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
                         "<soap:Body>"
                         "<%@ xmlns=\"%@\">"
                         "%@"
                         "%@"
                         "</%@>"
                         "</soap:Body>"
                         "</soap:Envelope>"
                         ,method, namespace, paramStr, paramInt, method];

//NSURLConnection生成
    NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMsg length]];
    NSString *soapAction = [NSString stringWithFormat:@"%@%@%@", namespace, method];

    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];  
    [req addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [req addValue:soapAction forHTTPHeaderField:@"SOAPAction"];
    [req addValue:msgLength forHTTPHeaderField:@"Content-Length"];
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody:[soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
 
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];

呼び出しメソッド名
メソッド名は名前だけで、パラメータの型や個数は関係ありません。

リクエストに含めるパラメータ
SOAPリクエストメッセージの組み立て時は文字列なので、リクエストを出すiOSアプリ側ではデータ型そのものを意識することはありません。しかし、当然ながらサーバー側で型変換に失敗するとエラーとなります。
サーバー側はメソッドの引数で指定した型に変換して引き渡します。もしなければ型に応じた規定値となります(null, 0など)。リクエストに含まれていてもサーバー側のメソッドに一致する名前のパラメータがない場合は無視されます。
SOAP 要求メッセージの構造 「入力パラメーターの処理」

関連Blog

iOS アプリからのSOAP/WebServiceへのアクセス
SOAP レスポンスの受信
SOAP レスポンスのパース
バイナリデータのSOAPレスポンス
SOAPリクエスト/レスポンスとの同期

0 件のコメント: