—————————
※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つでできます。
良かったら参考にしてみてください。
—————————
コメント