Simple&Natural
ImageCropper Lib와 okHttp3를 이용한 이미지 서버 업로드 본문
본 포스팅은 2018. 12. 4. 0:11 네이버 블로그에 작성했던 글을 이전한 것임
ImageCropper를 이용하여 이미지를 수정 및 받아오고 okHttp3를 통해 서버에 업로드하는 과정이 필요했다.
매우 많은 우여곡절 끝에... (결론적으로 파일객체 생성과 php권한 및 용량 문제가 메인이었음...)
성공하게 되었다.
기본적으로 핵심 원리는
1. 이미지의 경로를 불러오고
2. 이를 이용하여 파일 객체를 생성한 다음
3. Http 통신을 사용하여 서버에 업로드
로 구분된다.
ImageCropper 라이브러리는 수정된 이미지를 갤러리가 아닌 Cache 폴더에 저장하게 된다.
경로를 찾아보면 휴대폰에서 직접 찾아 들어간다는 기준 하에 "Android/data/패키지명/Cache/pickImageResult.jpeg"
로 저장된다. 하지만 여기서 이 경로를 직접 사용하여 파일 객체를 만들게 되면 카메라로 촬영한 사진만 있고
갤러리에서 불러온 것은 보이지 않는다... 그럼 이놈은 어디에 저장되는 건지 아직도 오리무중;;
이건 나중에 해결하기로 하고 일단 카메라와 갤러리를 통해 작업한 이미지를 전부 불러올 수 있게 하려면
onActivityResult에서 Intent 파라미터로 저장된 data를 통해 uri를 얻어야 한다.
이 uri를 또 그냥 갖다가 넣으면 파일 객체는 만들어지지 않고 반드시 getPath를 통해 얻은 경로를 넣어줘야 한다.
사실 파일만 잘 만들 수 있으면 Http로 서버에 던져버리는 건 별로 어렵지 않다. (안드로이드 스튜디오 내에서는...)
이후에 문제가 생길만한 부분은 리눅스 폴더권한과 php파일 용량 제한 정도일까?
반드시 이부분을 꼭 확인하도록 하자.
권한 부분은 리눅스 log 폴더에 error.log를 보면 대충 permission denied라고 친절하게 알려주는데
이 용량문제는 로그도 안찍어줘서 혼자 머리싸매고 고민하다가 문득 이거아닐까 싶어서 보다가 해결했다.
어떤 이미지는 올라가고 어떤 건 또 올라가지를 않아서 왜그럴까에서 힌트를 얻음.
내 경우에는 2MB가 제한용량이었는데 3MB를 처넣으려고 했으니 올라갈리가 있나...
아무튼 이미지 업로드 문제는 여기까지 해서 대충 끝냈다.
<라이브러리 build 시 소스>
implementation("com.squareup.okhttp3:okhttp:3.12.0")
api 'com.theartofdev.edmodo:android-image-cropper:2.8.+'
CropImageView.CropResult result = CropImage.getActivityResult(data);
여기서 data는 onActivityResult의 Intent 파라미터임
Uri resultUri = result.getUri();
Uri resultOriginalUri = result.getOriginalUri();
String getUriPath = resultUri.getPath(); //파일생성 가능
String getOriginalUriPath = resultOriginalUri.getPath();
Log.d("test3", "result uri : " + resultUri.toString());
Log.d("test3", "result original uri : " + resultOriginalUri.toString());
Log.d("test3", "result uri path : " + getUriPath);
Log.d("test3", "result original path : " + getOriginalUriPath);
test3의 로그는 다음과 같다.
<카메라를 이용해 촬영한 사진>
result uri : file:///data/user/0/com.example.msg_b.librarytest/cache/cropped4137546372064436160.jpg
result original uri : file:///storage/emulated/0/Android/data/com.example.msg_b.librarytest/cache/pickImageResult.jpeg
result uri path : /data/user/0/com.example.msg_b.librarytest/cache/cropped4137546372064436160.jpg
result original path : /storage/emulated/0/Android/data/com.example.msg_b.librarytest/cache/pickImageResult.jpeg
<갤러리 에서 가져온 사진>
result uri : file:///data/user/0/com.example.msg_b.librarytest/cache/cropped6146047158517801312.jpg
result original uri : content://media/external/images/media/6599
result uri path : /data/user/0/com.example.msg_b.librarytest/cache/cropped6146047158517801312.jpg
result original path : /external/images/media/6599
총 핵심사항 정리
1. btn_upload 버튼에 ImageCropper를 실행
btn_upload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
CropImage.activity().start(MainActivity.this);
}
});
2. onActivityResult에서 작업한 이미지의 경로를 받아온 후 MyImgTask에 파라미터로 보냄.
중간에 AbsoluteCacheUri는 직접 디바이스에서 찾은 CroppedImage의 경로인데
이 경로를 쓰면 카메라로 촬영한 사진만 저장되고 갤러리에서 가져온 사진은 불러오지 못함.
CropImage.getActivityResult(data).getUri().getPath(); 를 이용해 얻은 경로를 넣어주면
카메라와 갤러리 작업물 둘다 불러올 수 있음.
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
CropImageView.CropResult result = CropImage.getActivityResult(data);
Uri resultUri = result.getUri();
Uri resultOriginalUri = result.getOriginalUri();
String getUriPath = resultUri.getPath();
String getOriginalUriPath = resultOriginalUri.getPath();
Log.d("test3", "result uri : " + resultUri.toString());
Log.d("test3", "result original uri : " + resultOriginalUri.toString());
Log.d("test3", "result uri path : " + getUriPath);
Log.d("test3", "result original path : " + getOriginalUriPath);
String AbsoluteCacheUri = Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/cache/pickImageResult.jpeg";
Log.d("test4", AbsoluteCacheUri);
new MyImgTask(getUriPath).execute();
} else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
}
}
3. 최종적으로 네트워크 통신을 통하여 이미지를 서버에 전송하고 json형태로 응답을 받아오는 AsyncTask임.
/** 이미지 웹서버 업로드 태스크 **/
class MyImgTask extends AsyncTask<String, Void, String> {
private String Path;
public MyImgTask(String path) {
this.Path = path;
}
ProgressDialog mDialog = new ProgressDialog(MainActivity.this);
@Override
protected void onPreExecute() {
super.onPreExecute();
mDialog.show();
}
@Override
protected String doInBackground(String... strings) {
File srcFile = new File(Path);
String result = null;
if(srcFile.exists()){ // 파일이 존재하는 경우
if(srcFile.isFile()){ //파일이 맞으면
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "test2", RequestBody.create(MediaType.parse("image/jpg"), srcFile))
.build();
Request request = new Request.Builder()
.url("내 php파일 경로")
.post(requestBody)
.build();
Call call = new OkHttpClient().newCall(request);
Log.d("filetest", request.body().toString());
try {
Response response = call.execute();
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
Log.d("filetest", "try 실패 : " + e.toString());
}
}
else { // 이거 파일이 아닌데?
Log.d("filetest", "이거 파일 아닌데?");
}
}
else {
Log.d("filetest", "파일이 없는데?");
}
return result;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d("filetest", "response : "+s);
mDialog.dismiss();
}
}
4. php파일은 다음과 같음
권한과 uploaded file의 max size는 필히 리눅스에서 설정해줘야함.
<?php
$target_dir = "";
$target_file_name =$target_dir .basename($_FILES["file"]["name"].".jpg");
$response = array();
//Check if image file is a actual image or fake image
if(isset($_FILES["file"])) {
if(move_uploaded_file($_FILES["file"]["tmp_name"], $target_file_name)) {
$success = true;
$message = "successfully uploaded";
} else {
$success = false;
$message = "Error while uploading";
}
} else {
$success = false;
$message = "Required Field Missing";
}
$response["success"] = $success;
$response["message"] = $message;
echo json_encode($response);
?>
------------------------------------------------------------------------------------------------------------------------
<2018-12-04 추가내용>
- 파일객체 생성 가능한 경로 최종 정리
String croppedPath = result.getUri().getPath(); /** 가능 **/
String croppedOriginalPath = result.getOriginalUri().getPath(); /** 가능 **/
String croppedUri = result.getUri().toString(); /** 불가능 **/
String croppedOriginalUri = result.getOriginalUri().toString(); /** 불가능 **/
Log.d("filetest", "Path : " + croppedPath);
Log.d("filetest", "Original Path : " + croppedOriginalPath);
Log.d("filetest", "Uri : " + croppedUri);
Log.d("filetest", "Original Uri : " + croppedOriginalUri);
'안드로이드(Android) > 이슈 및 해결' 카테고리의 다른 글
Android Module 추가 방법 (0) | 2019.12.13 |
---|---|
CMake build중 발생하는 오류 (0) | 2019.12.13 |
안드로이드 Action Bar 사용 시 Item의 Icon과 Title이 동시에 보이지 않는 이슈 (0) | 2019.12.13 |
RecyclerView가 item Position을 제대로 찾지 못하는 이슈 (0) | 2019.12.13 |
실시간 채팅앱 개발의 여러가지 이슈 (0) | 2019.12.13 |