[jQuery File Upload]
前回からかなり時間が過ぎてしまいましたが、サーバーサイドでapktoolを使ってapkファイルを解凍して、アプリのバージョンやパッケージ名apkファイルの内容を返すところを実装します。jQuery File Uploadも前回は6.4.2だったのが、7.0.1にまで上がっています。今回は、最新の7.0.1を利用します。
Webページからのapkファイルアップロードではなく、直接curlコマンドからも実行できるように実装しています。こうしておけば、WebページのUIは、jQUery File Uploadで実装してもよいし、他のUIライブラリで実装も可能です。
UploadApkHander.php
jQuery File UploadのPHPバージョンのサーバサイドであるUploadHandlerクラスを継承して、UploadApkHandlerクラスを作成します。UploadHandlerクラスは、jQuery File Uploadのルートディレクトリ下のserver/phpディレクトリにあります。
<?php require_once('UploadHandler.php'); class UploadApkHandler extends UploadHandler { // apktoolのパス const APKTOOL = '[APK_TOOL_PATH]/apktool d --frame-path [APK_TOOL_PATH]/apktool '; // 今回はuser_idはセッションIDを利用する。 private $user_id = null; function __construct() { // UploaderHanderを初期化する。 parent::__construct(array( 'user_dirs' => true, 'param_name' => 'file', 'accept_file_types' => '/apk$/i', 'upload_dir' => '[APKUPLOADER_FILE_PATH]/apkuploader/files/', 'apk_dir' => '/apk' ), true, null); } /** * AndroidManifest.xmlをxpathでパースする。 */ protected function get_apk_info($apk_file) { $dir = $this->options['upload_dir'] . $this->user_id . $this->options['apk_dir']; $manifest = simplexml_load_file($dir . '/AndroidManifest.xml'); $apk_file->package = (string)$manifest->attributes()->package; $apk_file->versionCode = (string)$manifest->attributes('android', true)->versionCode; $apk_file->versionName = (string)$manifest->attributes('android', true)->versionName; $label = $manifest->application->attributes('android', true)->label; list(, $label) = explode('/', $label); $strings = simplexml_load_file($dir . '/res/values/strings.xml'); list(, $name) = each($strings->xpath("/resources/string[@name='" . $label . "']")); $apk_file->app_name = (string)$name; $apk_file->icon_image = $this->options['upload_url'] . $this->user_id . $this->options['apk_dir'] . '/res/drawable-hdpi/ic_launcher.png'; return $apk_file; } /** * アップロードしたファイルをapktoolで解凍する。 * @Override */ protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, $index = null, $content_range = null) { $file = parent::handle_file_upload($uploaded_file, $name, $size, $type, $error, $index, $content_range); $apk_file = new StdClass; $apk_file->url = $file->url; $apk_file->name = $file->name; $apk_file->size = $file->size; $dir = $this->options['upload_dir'] . $this->user_id; $cmd = self::APKTOOL . $dir . '/' . $apk_file->name . ' ' . $dir . $this->options['apk_dir']; // apktoolを実行 exec($cmd, $output, $status); // AndroidManifest.xmlをパース $this->get_apk_info($apk_file); // アップロードしたファイルを削除 exec('rm -rf ' . $dir); return $apk_file; } /** * user_idとしてセッションIDを設定し、保存する。 * @Override */ protected function get_user_id() { @session_start(); $this->user_id = session_id(); return $this->user_id; } }
index.php
さきほどのクラスをコンストラクトして、ファイルを受信します。先ほどのhttp:/www.paads.net/apkuploader/index.phpを呼び出すと、ファイルアップロードが始まります。
<?php require_once('UploadApkHandler.php'); new UploadApkHandler(); ?>
curlコマンドから実行
アップロードしたいapkファイルを準備して、以下のようにコマンドを実行します。
$ curl -F file=@test.apk http://www.paads.net/apkuploader/
アップロードが完了すると、以下のようなJSONデータが返ってきます(見やすいように整形しています)。
"file":[{ "url" : "http://www.paads.net/apkuploader/files/3dbbb9d7f5b6ac8233a0d8fc7cf57321\/test.apk", "name" : "test.apk", "size" : 372225, "package" : "jp.co.notice.hoge", "versionCode" : "2", "versionName" : "1.0", "app_name" : "Hoge", "icon_image" : "http://www.paads.net/apkuploader/files/u3dbbb9d7f5b6ac8233a0d8fc7cf57321/apk/res/drawable-hdpi/ic_launcher.png" }]}
実際の実行結果サンプルとして、http://www.paads.net/apkuploader/を公開しています。curlコマンドで実行すれば、アップロードされます。
UIがないので、わかりにくかもしれませんが、ウェブページのUIとべったりのサーバサイドサービスを設計・実装してしまうと、使いにくくなりますし、ユニットテストも難しくなります。
アップロードされた後、apkファイルを解凍し、AndroidManifest.xmlをパースして、アプリの情報をJSONで返します。アップロードしたファイルをその後消去していますので、ご安心ください。
後は、ファイルはそのまま保存し、アプリの情報はデータベースに保存すれば、apkファイルのバージョン管理ができます。RESTfulのインタフェースを加えていけば、色々なウェブアプリと連動できるようになります。もう少し、手を加えて、アプリの自動更新のサーバサイドのサービスとして実装することも可能です。