技術顧問の増田です。
前回までは、Web API を使ってサーバーからデータを取得する機能を使ってアプリを作ってきました。今回は、その逆で、Web API を使ってサーバーにデータを送信する機能を使ってアプリを作ります。
Android アプリでアンケートを入力して、サーバーに送信する「簡易アンケート」アプリを作ってみましょう。
サンプルコードは https://github.com/moonmile/sg-xamarin-sample にあります。
バックナンバー
- 第1回 C#で自作Android アプリを作ろう:出帆準備編
- 第2回 C#で自作Android アプリを作ろう:試験運用編
- 第3回 C#で自作Android アプリを作ろう:時計アプリを作る
- 第4回 C#で自作Android アプリを作ろう:RSSを取得してリスト表示
- 第5回 C#で自作Android アプリを作ろう:Web APIで路線情報を表示
- 第6回 C#で自作Android アプリを作ろう:Twitter APIでファボリストを取得
- 第7回 C#で自作Android アプリを作ろう:簡易アンケートを作ろう
- 第8回 C#で自作Android アプリを作ろう:カメラ機能を使おう
POSTとは何か?
アンケートツールでは、サーバーにWebサーバーを使います。Webサーバーには、HTTP プロトコルでデータを送信するのですが、これは一般的にブラウザで閲覧をしているときと同じ「プロトコル」です。プロトコルというのは「約束事」ですから、世の中にはいろいろなプロトコルがあります。場合によっては自作プロトコルを作ることもできます。が、まあ、一般的な Web サーバーでは「HTTP プロトコル」が使われているので、この使い方を覚えると、大抵のWebサーバーアクセスができるというということになります。
フォーム入力を送信する
HTTP プロトコルの詳細は、別に探して貰うということで、ここではサンプルに必要なところだけ解説しましょう。
- HTTPプロトコルのPOSTメソッドを使う
- Content-Typeを「application/x-www-form-urlencoded」で送る。
- 戻り値は、HTML形式などで返ってくる。
ことだけ覚えておけばokです。
Content-Typeが「application/x-www-form-urlencoded」ってのは、ブラウザのフォーム(formタグやinputタグなど)を使ってサーバーと送受信する、いわゆるCGIな古くからある方式ですが、いまでも十分現役です。一方で、ajax など非同期で JSON や XML 形式のデータを送る方法もあります。こっちの方式のほうが、Android アプリで作るときは楽なのですが(Web APIと同じ作り方ができますからね)、一般的な Web サーバーの応答をそのまま使う場合は、Android アプリから「application/x-www-form-urlencoded」で送信できるようになったほうが、応用の幅が広がります。
図のように、
- ブラウザ
- コンソールアプリ
- Android アプリ
の3種類で同じ HTTP サーバーを相手にすることができるからです。
PHPでサーバーを作る
Web APIの解説では、駅データ.jp を使いましたが、今回は自前で Web サーバーを用意してみましょう。既に Linux などで LAMP 環境がある場合は、それを使ってもいいでしょう。
xampp を使う
Windows 上で、LAMP 環境を作るときは xampp を使うと便利です。Apache + MySQL/MariaDB + PHP の環境がさっくり作れます。
index.php
Windows 環境に /xampp/htdocs/svQuest フォルダを作って、index.php を置きます。単純なアンケートツールですね。
sgQuestion sample page
form の method 属性に「post」を指定して、送信先を「post.php」にしておきます。
post.php
もうひとつ、post.php を作ります。
sgQuestion post check
ポストされた内容を確認する
name:
join:
horoscope:
memo:
本来ならば、MySQL に保存するところですが、面倒…いや、ここでは実験なので値を返すだけにします。
ブラウザから呼び出し
ブラウザを使って動作確認をしておきましょう。
アンケート画面

確認画面

要求ヘッダ
HTTP プロトコルがどういう動きをしているのかを見るために F12 キーを押して、ネットワークの状態を確認しておきます。
要求本文
POST メソッドで送信するデータはこんな感じですね。
ブラウザから、送信するときはサーバーから送られてきた画面に対してぽちぽちやれば大丈夫ですが、これを自動化するにはどうしたらいいでしょうか?
という訳で、Android で実装するまえに、コンソールアプリを作って詳細を確認してみましょう。
コンソールから呼び出し
コンソールアプリから HTTP プロトコルを使って Web サーバーにアクセスするときは HttpClient クラスを使います。フォーム入力のような POST メソッドも手軽にできるようになっています。
コード
class Program
{
static void Main(string[] args)
{
var prog = new Program();
var t = prog.Go();
t.Wait();
}
async Task Go()
{
var hc = new HttpClient(); // ①
var dic = new Dictionary<string, string>(); // ②
dic["name"] = "masuda";
dic["join"] = "1";
dic["horoscope"] = "Taurus";
dic["memo"] = "これはメモです";
var cont = new FormUrlEncodedContent(dic); // ③
var url = "http://localhost/svQuest/post.php"; // ④
var req = await hc.PostAsync(url, cont); // ⑤
var html = await req.Content.ReadAsStringAsync(); // ⑥
Console.WriteLine(html);
}
}
- HttpClient のオブジェクトを生成
- 送信するパラメータは、Dictionary で作ります。
- キーと値のペアができたら、FormUrlEncodedContent でフォーム用にエンコードします。
- 送信先は post.php ですね。
- POST は、PostAsync メソッドを呼び出して実行します。
- 応答は ReadAsStringAsync を使って一括で取得すればokです。
結果
うまくいくと、こんな風に登録した結果が帰って来ます。
Android から呼び出し
コンソールアプリでの動作が確認できたところで、Android に実装していきましょう。
画面デザイン
デザイナを使ってぽちぽちとデザインします。面倒…じゃなくて、わかりやすいように LinearLayout でペタペタ作っていきましたが、もうちょっとデザインしてもokです。名前さえ変えなければ、どのように変えても構いません。
axml
コード
MainActivity.cs は 100行ちょっとで済みます。
[Activity(Label = "sgQuestionnaire", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
// コントロール
EditText editName;
EditText editMemo;
Spinner spJoin;
RadioButton radioJoin1, radioJoin2, radioJoin3;
List Horos;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
editName = FindViewById(Resource.Id.editName); // ①
editMemo = FindViewById(Resource.Id.editMemo);
spJoin = FindViewById(Resource.Id.spinner1);
radioJoin1 = FindViewById(Resource.Id.radioJoin1);
radioJoin2 = FindViewById(Resource.Id.radioJoin2);
radioJoin3 = FindViewById(Resource.Id.radioJoin3);
Button btnPost = FindViewById
/// /// private async void BtnPost_Click(object sender, System.EventArgs e) { // 画面からデータを取得 string name = editName.Text; // ⑤ string memo = editMemo.Text; if ( spJoin.SelectedItemPosition == 0 ) { new AlertDialog.Builder(this) // ⑥ .SetMessage(“星座を選択してください”) .Show(); return; } string horo = Horos[spJoin.SelectedItemPosition].Id; string join = “1”; if (radioJoin1.Checked) join = “1”; if (radioJoin2.Checked) join = “2”; if (radioJoin3.Checked) join = “3”; var html = await Go(name, join, horo, memo); // ⑦ // 結果を表示 new AlertDialog.Builder(this) // ⑧ .SetMessage( html ) .Show(); return; } async Task Go(string name, string join, string horo, string memo) // ⑨ { var hc = new HttpClient(); var dic = new Dictionary<string, string>(); dic[“name”] = name; dic[“join”] = join; dic[“horoscope”] = horo; dic[“memo”] = memo; var cont = new FormUrlEncodedContent(dic); // 呼び出しのIPアドレスは変更すること var url = “http://172.16.0.11/svQuest/post.php”; var req = await hc.PostAsync(url, cont); var html = await req.Content.ReadAsStringAsync(); return html; } } public class Horo // ⑩ { public string Id { get; set; } public string Text { get; set; } public override string ToString() { return this.Text; } }
簡単にコードの解説をしておきましょう。
- FindViewById メソッドでコントロールを取ってきます。
- 選択用の Spinner に設定するリストを作ります。
- ArrayAdapter を作っておいて、
- Adapter プロパティに設定します。
- 「投稿」ボタンをタップしたときに、各コントロールから値を取得します。
- 入力時のエラーメッセージは「AlertDialog.Builder」を使うと便利です。
- 投稿時のメソッドはコンソールアプリからそのままコピーしています。投稿先の URL アドレスを記述しなおしてください。
- 結果を表示します。
- 投稿時の処理をコピペします。
- Spinner に設定する Horo クラスを作っておきます。
実行
コードができたらエミュレータで実行してみましょう。
ブラウザやコンソールアプリと同じようにアンケートが投稿できるようになりましたね。
サーバーを.NET Coreで作る
さて、LAMP サーバーの場合は、PHP を使ってサーバーサイドのコードを記述しましたが、ASP.NET Core MVC を使うこともできます。
この部分は、おまけなので、ざっとコードだけ示しておきます。詳細は https://github.com/moonmile/sg-xamarin-sample/tree/master/src/sgQuestionnaire/sqQuestSvCore にあります。
Model
MVC パターンの Model クラスです。
public class Quest
{
[Display(Name = "名前")]
public string name { get; set; }
[Display(Name = "参加")]
public int join { get; set; }
[Display(Name = "星座")]
public string horoscope { get; set; }
[Display(Name = "メモ")]
public string memo { get; set; }
public static List horoscopes
{
get
{
var Horos = new List();
Horos.Add(new Horo() { Id = "", Text = "選択してください" });
Horos.Add(new Horo() { Id = "Aries", Text = "おひつじ座" });
Horos.Add(new Horo() { Id = "Taurus", Text = "おうし座" });
Horos.Add(new Horo() { Id = "Gemini", Text = "ふたご座" });
Horos.Add(new Horo() { Id = "Cancer", Text = "かに座" });
Horos.Add(new Horo() { Id = "Leo", Text = "しし座" });
Horos.Add(new Horo() { Id = "Virgo", Text = "おとめ座" });
Horos.Add(new Horo() { Id = "Libra", Text = "てんびん座" });
Horos.Add(new Horo() { Id = "Scorpio", Text = "さそり座" });
Horos.Add(new Horo() { Id = "Saggitarius", Text = "いて座" });
Horos.Add(new Horo() { Id = "Capricorn", Text = "やぎ座" });
Horos.Add(new Horo() { Id = "Aquarius", Text = "みずがめ座" });
Horos.Add(new Horo() { Id = "Pisces", Text = "うお座" });
return Horos;
}
}
}
public class Horo
{
public string Id { get; set; }
public string Text { get; set; }
}
Controller
Controller クラスを作っておきます。登録時には Create メソッドが呼び出されます。
public class QuestController : Controller
{
// GET: //
public IActionResult Index()
{
ViewData["horoscopes"] = new SelectList( Quest.horoscopes, "Id", "Text" );
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create([Bind("name,join,horoscope,memo")] Quest quest)
{
if (ModelState.IsValid)
{
// 実際は保存処理が入る
// _context.Add(quest);
// await _context.SaveChangesAsync();
return View("Result", quest);
// return RedirectToAction("Post");
}
return View(quest);
}
}
View
ブラウザから入力するための View を作っておきます。
@model sgQuestMvcCore.Models.Quest
@{
ViewData["Title"] = "Create";
}
Create
MainActivity.cs の書き替え
投稿時の URL が異なるので、書き替えて実行します。
async Task Go(string name, string join, string horo, string memo)
{
var hc = new HttpClient();
var dic = new Dictionary<string, string>();
dic["name"] = name;
dic["join"] = join;
dic["horoscope"] = horo;
dic["memo"] = memo;
var cont = new FormUrlEncodedContent(dic);
// 呼び出しのIPアドレスは変更すること
// var url = "http://172.16.0.11/svQuest/post.php";
// .NET Core のサンプルの場合
var url = "http://172.16.0.11:5000/Quest/Create";
var req = await hc.PostAsync(url, cont);
var html = await req.Content.ReadAsStringAsync();
return html;
}
実行
アンケートの入力と「投稿」ボタンまでは同じ動作になります。.net core のサーバーを「dotnet run」で動かして 5000 番ポートで待ち受けます。
戻り値が、ちょっとうまく表示できていない(HTMLデータが多すぎる)ので調節が必要ですが、ひとまず登録できていることがわかります。
まとめ
如何だったでしょうか? Android からサーバーにアクセスするときに HttpClient を使えば、結構いろいろなことができることが分かります。画面はチープですが、サーバーと組み合わせれば、サーバー側で独自で拡張することもできるので、同じアプリであっても後から機能をアップすることができます。また、逆にサーバーは同じであってもクライアントの UI を変更することで使いやすい画面を作ることも可能です。
次回は、Android 自身の機能を使ってアプリを作ります。カメラを使って、撮影の基本的な部分を作ってみます。
お楽しみに。










