—————————
※2014年3月22日 追記
この方法だとAndroid4.0以上でエラーとなると思います。
エントリーの最後にAsyncTaskを使ったもっと簡単な方法を記載しています。
—————————
Androidアプリでサーバに画像をアップロードする方法。
まず、以下のjarファイルをダウンロードしてきて、プロジェクト内の「libs」フォルダに格納する。
apache-mime4j-core-0.7.2.jar(ダウンロードはこちら)
httpclient-4.2.5.jar(ダウンロードはこちら)
httpcore-4.2.4.jar(ダウンロードはこちら)
httpcore-nio-4.2.4.jar(ダウンロードはこちら)
httpmime-4.2.5.jar(ダウンロードはこちら)
で、本来であれば、「カメラ」や「ギャラリーから選択」にintentして画像を取得する訳ですが、割愛。
SDカードの中のファイルを直接指定してサーバにアップロードしています。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String sUrl = "http://hogehoge.com/uploads/"; String fileName; String filePath; // 写真ディレクトリ用パス設定 String strDirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/download/"; // ディレクトリの作成 makeDirectory(strDirPath); // ファイル名フォーマット取得 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); // ファイル作成、書き込み //fileName = dateFormat.format(today) + ".png"; fileName = "001.png"; filePath = strDirPath + fileName; int size = 2048; FileOutputStream stream = null; try { stream = new FileOutputStream(filePath); } catch (FileNotFoundException e1) { e1.printStackTrace(); } try { stream.write(size); } catch (IOException e) { e.printStackTrace(); } try { stream.close(); } catch (IOException e) { e.printStackTrace(); } // サーバへ画像を送信 HttpClient client = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(sUrl); // Basic認証するUserとPasswordを設定 UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( "username", "password" ); AuthScope scope = new AuthScope( httpPost.getURI().getHost(), httpPost.getURI().getPort() ); ((AbstractHttpClient) client).getCredentialsProvider().setCredentials( scope, credentials ); File upfile = new File( filePath ); MultipartEntity mentity = new MultipartEntity(); mentity.addPart("upfile", new FileBody(upfile)); // レスポンス取得 httpPost.setEntity(mentity); HttpResponse response = null; try { response = client.execute(httpPost); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // レスポンス取得 HttpEntity entity = response.getEntity(); String res = null; try { res = EntityUtils.toString( entity, "UTF-8" ); } catch (ParseException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // リソース解放 try { entity.consumeContent(); } catch (IOException e) { e.printStackTrace(); } // 切断 client.getConnectionManager().shutdown(); TextView txtResult = (TextView) findViewById(R.id.txtResult); txtResult.setText(res.toString()); } // ディレクトリの作成 private boolean makeDirectory(String strDirPath) { boolean ret = false; File dir = new File(strDirPath); if (!dir.exists()) { ret = dir.mkdirs(); } else { ret = true; } return ret; }
で、サーバ側では何をしているかというと、画像を受け取ってリネーム後、指定したディレクトリに移動。
そして300×300pxの正方形のサムネイルを生成しています。
< ?php /* ======================================================================== * * @category Application of hoge * @author woodsmall inc. <hoge@woodsmall.co.jp> * @copyright 2013 woodsmall inc. * @version Rev 1.0.0 * @link https://woodsmall.co.jp * * @brie 画像のアップロードを行い、同時にサムネイルを生成する * @note * * @param N/A * @return 正常:アップロードファイル名 異常:エラーメッセージ * ======================================================================== */ // パス設定 define("ROOT_PATH", realpath("../")); $Y = ROOT_PATH. "/images/". date("Y"); $Ym = ROOT_PATH. "/images/". date("Y/m"); $Ymd = ROOT_PATH. "/images/". date("Y/m/d"); $rename_dir = $Ymd. "/". date("YmdHis"). ".png"; $thumb = $Ymd. "/". date("YmdHis"). "-thumb.png"; $rename_file = date("YmdHis"). ".png"; if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) { if (move_uploaded_file($_FILES["upfile"]["tmp_name"], $_FILES["upfile"]["name"])) { chmod("files/" . $_FILES["upfile"]["name"], 0644); //echo $_FILES["upfile"]["name"] . "をアップロードしました。"; // ディレクトリ作成 mkdir( $Y, 0711 ); mkdir( $Ym, 0711 ); mkdir( $Ymd, 0711 ); // 画像をリネームして移動 rename($_FILES["upfile"]["name"], $rename_dir); // サムネイルを生成 $file = $_FILES["upfile"]["name"]; $image = imagecreatefrompng( $file ); if ($image) { $width = imagesx( $image ); $height = imagesy( $image ); if ( $width >= $height ) { //横長の画像の時 $side = $height; $x = floor( ( $width - $height ) / 2 ); $y = 0; $width = $side; } else { //縦長の画像の時 $side = $width; $y = floor( ( $height - $width ) / 2 ); $x = 0; $height = $side; } $thumbnail_width = 300; $thumbnail_height = 300; $thumbnail = imagecreatetruecolor( $thumbnail_width, $thumbnail_height ); // imagecopyresized( $thumbnail, $image, 0, 0, $x, $y, $thumbnail_width, $thumbnail_height, $width, $height ); imagecopyresampled( $thumbnail, $image, 0, 0, $x, $y, $thumbnail_width, $thumbnail_height, $width, $height ); $result = imagepng( $thumbnail, $thumb ); if ($result) { echo $rename_dir; } else { echo "ERROR imagepng!!n". $Ymd; } } else { echo "ERROR imagecreatefrompng!!n"; } // メモリ上の画像データを破棄 imagedestroy($image); imagedestroy($thumbnail); } else { echo "ファイルをアップロードできません。"; } } else { echo "ファイルが選択されていません。"; }
できれば、AndroidとiPhoneで共通したサーバ側のAPIを使用したいところなんだけど、iPhoneで画像をアップする方法は若干違うっぽい。
なので、APIもiPhone用を開発しなきゃっぽい。
iPhoneの画像アップロード方法は、また後ほど。
—————————
※2014年3月22日 追記
AsyncTaskを使ったソース(Android側)もスッキリする書き方です。
1.jarをダウンロードし、プロジェクトのlibsフォルダに配置
httpcore-4.3.4.jar(ダウンロードはこちら)
httpmime-4.3.3.jar(ダウンロードはこちら)
※こちらはアップデートされているので、最新版をダウンロード
2.AsyncTaskを継承したクラスを作成
import java.io.File; import java.io.IOException; import jp.co.tokyobay.btnet.R; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.widget.Toast; @SuppressWarnings("deprecation") public class UploadAsyncTask extends AsyncTask<String , Integer, Integer> { public Context context; private String ReceiveStr; public int iCnt; public UploadAsyncTask(Context context) { this.context = context; } @SuppressWarnings("deprecation") @Override protected Integer doInBackground(String... params) { try { String fileName = params[0]; // URLパラメータを取得 String sId= ""; /* 処理 */ // パラメータ作成 String sPar = ""; if (mCommon.isNullOrEmpty(sId)) { sPar = "?" + Constants._ID + "="; } else { sPar = "?" + Constants._ID + "=" + sId; } HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(Constants.SERVER_URL + Constants.API_UPLOAD_AUDIO + sPar); ResponseHandler</string><string> responseHandler = new BasicResponseHandler(); MultipartEntity multipartEntity = new MultipartEntity(); File file = new File(fileName); FileBody fileBody = new FileBody(file); multipartEntity.addPart("upfile", fileBody); httpPost.setEntity(multipartEntity); ReceiveStr = httpClient.execute(httpPost, responseHandler); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return 0; } @Override protected void onPostExecute(Integer result) { // サーバ側phpでechoした内容を表示 Toast.makeText(context, ReceiveStr, Toast.LENGTH_LONG) .show(); } }
mCommonってのは、共通クラスです。
Constantsってのは、共通の定数を定義したクラスです。
Constants.SERVER_URL + Constants.API_UPLOAD_AUDIOにサーバ側のURLが入っています。
サーバ側で処理分岐させるため、URLパラメータを付与しています。
サーバ側のphpが呼ばれるとonPostExecute()メソッドが呼ばれます。
ここでサーバ側で出力した内容によって処理分岐とか出来ます。
3.呼び出し側のActivity
// サーバにアップロード UploadAsyncTask task = new UploadAsyncTask( me); task.context = me; task.iCnt = iCount; task.execute(filePath);
“me”はローカル変数で、(アクティビティ名).thisというContextが入っています。
filePathにローカルファイルのパスが入っています。
これでやれば、サーバとのやりとりも非同期でやってくれるし、ソースもスッキリ。
jarファイルも2つでできます。
良かったら参考にしてみてください。
—————————
コメント