Androidでサーバに画像をアップロードする方法

  •  

 

—————————
※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つでできます。

良かったら参考にしてみてください。
—————————

関連記事

コメント

この記事へのコメントはありません。

TOP