emu雑記

C#erな人が書いているブログです。最近、javaを始めました。なんかいろいろやってます。

AndroidアプリからASP.NET Web APIへの接続方法 その1

Androidアプリから、ASP.NET Web APIへの接続をまとめました。

この1週間ハマりにハマって、やっと解決しました。
といっても、原因は「画面描画スレッドでHTTPリクエストを投げていた為」にエラーになっていたというオチでした。

ほんと、慣れない言語は些細なことでハマってしまいますね。

ということで、やっと解決したのでまとめていきます。

ASP.NET Web APIの作成

まず、Visual Studio 2013を起動して、新しいプロジェクトから、ASP.NET Webアプリケーションを開きます。
f:id:emu717171:20131118215059j:plain

次に、Webアプリケーションの種類ですが、Web APIにチェックを付けます。
f:id:emu717171:20131118215245j:plain

このままOKをクリックして、プロジェクトが作成されます。
f:id:emu717171:20131123234453j:plain

ValuesController.csを開いて、

  • public void Post([FromBody]string value)

に、ブレークポイントを置いときましょう。
f:id:emu717171:20131124003057j:plain

IISのインストール

次に、ローカルIISをインストールします。
[コントロールパネル]から、[プログラムと機能]を選択します。
f:id:emu717171:20131124003238j:plain

左側の[Windowsの機能の有効化または無効化]をクリックします。
f:id:emu717171:20131123235133j:plain

[インターネット インフォメーション サービス]にチェックを付けて、その下のASP.NET 4.5にもチェックを付けておきましょう。
f:id:emu717171:20131123234501j:plain

インストールが完了したら、[ファイル名を指定して実行]から「inetmgr」でIISマネージャーが起動できると思います。
f:id:emu717171:20131123234639j:plain

とりあえず、Default Web Siteは起動しておきましょう。
f:id:emu717171:20131123235252j:plain

ローカルIISでのデバッグ設定

Visual Studio 2013に戻ります。

プロジェクトの[Properties] - [Web]を選択して、サーバーをローカルIISに変更します。
そして、[仮想ディレクトリの追加]をクリック。
f:id:emu717171:20131123234901j:plain

そしたら、F5ボタンを押してデバッグ実行を開始してください。
IEが起動されて、Webサイトが表示されていると思います。
f:id:emu717171:20131123235007j:plain

Web APIへのアクセス確認

IEのアドレスにhttp://localhost/[Webアプリケーション名]/api/valuesと打ち込んでみましょう。
values.jsonが取得されて中身が表示されていると思います。
f:id:emu717171:20131123213519j:plain

Androidアプリの作成

Androidアプリに移ります。

Android アプリケーション・プロジェクトを新規作成します。
f:id:emu717171:20131123235922j:plain

適当にアプリケーションを作成します。
f:id:emu717171:20131123235929j:plain

AndroidManifest.xmlにユーザーパーミッションで外部接続を許可します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.webapitest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <!--ココだよ-->    
    <uses-permission android:name="android.permission.INTERNET" />
    ...

MainActivityコンストラクタを編集します。
LoaderCallbacks を実装します。

package com.webapitest;

import org.apache.http.HttpResponse;

import android.os.Bundle;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
import android.view.Menu;

public class MainActivity extends Activity implements LoaderCallbacks<HttpResponse> {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Bundle bundle = new Bundle();
		getLoaderManager().initLoader(0, bundle, this);
	}

	@Override
	public Loader<HttpResponse> onCreateLoader(int id, Bundle bundle) {
		if (id == 0) {
			// ValuesAsyncLoaderの生成
			ValuesAsyncLoader loader = new ValuesAsyncLoader(this);
			// Web APIの呼び出し
			loader.forceLoad();
			return loader;
		}
		return null;
	}

	@Override
	public void onLoadFinished(Loader<HttpResponse> loader, HttpResponse response) {
		// 今回は何も処理しない
	}

	@Override
	public void onLoaderReset(Loader<HttpResponse> loader) {
		// 今回は何も処理しない
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

次に、ValuesAsyncLoaderを作成します。

package com.webapitest;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import android.content.AsyncTaskLoader;
import android.content.Context;

public class ValuesAsyncLoader extends AsyncTaskLoader<HttpResponse> {
	public ValuesAsyncLoader(Context context) {
		super(context);
	}

	@Override
	public HttpResponse loadInBackground() {
		try {
			DefaultHttpClient client = new DefaultHttpClient();
			HttpPost httpPost = new HttpPost();
			// URL
			httpPost.setURI(new URI("http://10.0.2.2/WebApplication1/api/values"));
			// Headerを設定
			httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
			// リクエストパラメータの設定()
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			nameValuePairs.add(new BasicNameValuePair("", "emu"));
			// POST データの設定
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
			// レスポンスを取得
			HttpResponse response = client.execute(httpPost);
			// 返す
			return response;
		} catch (Exception e) {
			return null;
		}
	}
}

ポイントを説明します。
httpリクエストはUIスレッドから実行すると落ちます。
なので、最近ではAsyncTaskLoaderをloadするのが主流ぽいです。
MainActivity の onCreateメソッドで

getLoaderManager().initLoader(0, bundle, this);

非同期実行しています。

次に、Web APIURIですが、http://10.0.2.2/を指定しています。
Visual Studioデバッグ実行している端末とAndroidエミュレーターが同一の場合には、Android エミュレーターから見たローカルマシンは10.0.2.2というIPアドレスが振られています。
127.0.0.1localhostAndroidエミュレーター自身となりますので注意が必要です。

また、Androidエミュレーターはポートが解放されていません。

通常のVisual Studio 2013のWebアプリケーション開発における、開発IISで振られたポートではAndroidエミュレーターASP.NET Web APIデバッグができないことに注意が必要です。

ここに注意しておけば、ハマることはないと思います。
無事にブレークポイントに引っかかってくれました。
f:id:emu717171:20131124004557j:plain