티스토리 뷰
지난 포스팅에서 아주 깔끔(?)하게 하이브리드앱에서 사용가능한 업로드 기능을 구현했는데
4.4.2 버전에서는 내장메소드가 제거되어있는터라
openfilechooser를 사용할수가 없는 비극의 현실이 있었습니다.
어떻게 하면될까요.
기획자와 잘 풀어서 여차저차 해결할수도 있겠지만
그래도 개발자인 이상 끈기를 가지고 도전해봐야겠죠.
4.4.2버전에서는 예외적으로 openfilechooser를 사용하지 않고 구현해야합니다.
이문제도 우회하여 풀어볼수 있는데요
바로 javascript interface를 사용하는것입니다.
android의 javascript interface를 사용하면 javascript 코드를 통하여 android 함수를 호출할수 있고,
반대로 android가 webview에 javascript 함수를 호출할수도 있습니다.
이점을 이용하여 사용자가 input type="file"을 터치하면 안드로이드의 함수를 실행하여 파일선택창을 강제로 띄워주고
파일을 선택한 다음에는 해당 파일을 decode한 string을 파라메터에 담아 webview가 쓸수 있도록 javascript함수를 호출해주는 원리죠.
마찬가지로 두개의 퍼미션이 필요합니다.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
그리고 웹뷰를 생성하는데
addJavascriptInterface를 이용해서 자바스크립트인터페이스를 적용해줍니다.
wv = (WebView) findViewById(R.id.webview); wv.setWebChromeClient(new WebChromeClient()); wv.setWebViewClient(new WebViewClient()); WebSettings set = wv.getSettings(); set.setJavaScriptEnabled(true); wv.loadUrl("http://test.com/upload.php"); wv.addJavascriptInterface(new JavaScriptInterface(this), "Android");
앞으로 webview의 웹페이지들은 Android 라는 이름의 객체에 접근할수 있게됩니다
public class JavaScriptInterface { private Context context; public JavaScriptInterface(Context context) { this.context = context; } @JavascriptInterface public void selectImage() { Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); startActivityForResult(intent, PICK_IMAGE_REQ_CODE); } }
selectImage()라는 함수를 만들었습니다.
webview의 페이지들은
Android.selectImage();
이렇게 자바스크립트를 호출하면 바로 이 안드로이드 메소드가 실행됩니다.
사용자가 선택한 파일을 받아서 다시 웹뷰로 전해주는 코드는 다음과 같습니다.
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PICK_IMAGE_REQ_CODE) { if (resultCode == Activity.RESULT_OK) { if (data != null) { Uri uri = data.getData(); new AsyncTask<uri, void,="" string="">() { @Override protected String doInBackground(Uri... params) { String mimeType = getMimeType(params[0]); File file = uriToFile(params[0]); String base64EncodedImage = fileToString(file); return "javascript:updateImage('" + mimeType + "', '" + base64EncodedImage + "');"; } @Override protected void onPostExecute(String result) { wv.loadUrl(result); } }.execute(uri); } } } }
updateImage라는 자바스크립트 함수를 호출하는 것이 보이나요?
그러면 아예 openfilechooser를 사용하지 않고 이런식으로 모든 버전을 구현해도 되지 않을까?
이렇게 생각하셨다면 짝짝짝 참 좋은 질문입니다.
이방법도 아쉬움이 존재하는데요
addJavascriptInterface 는 안드로이드 2.3 버전대에서 동작하지 않습니다...
2.3버전대를 무시하신다면 사용하셔도 좋긴합니다만
현재 제가 완성한 코드는 4.x 버전에서는 정상동작하나 5.0 이상버전에서 선택한 파일의 uri를 가져오는부분이(uriToFile 메소드) 완벽히 구현되지 않았습니다.
5.0이상에서도 동작가능한 코드로 수정하신분 계시면 github에 pull request 보내주시면 감사하겠습니다.
나머지 코드가 담긴 샘플 프로젝트는 AndroidJavascriptInterface 깃헙에 있습니다.
'정보' 카테고리의 다른 글
제3회 산업통상자원부 공공데이터 활용 비즈니스 아이디어 공모전 (0) | 2015.11.13 |
---|---|
제 1회 산업단지 정보 앱 개발 공모전 (0) | 2015.11.12 |
경북CKL 시제품 제작을 위한 '똘똘한+아이디어를 찾아라’ 모집공고 (0) | 2015.11.05 |
스타트업이 알아두면 좋은 앱스토어 심사시 reject 사유 12가지 (2) | 2015.11.03 |
윈도우7 씨디키가 뭔지 헷갈릴때 (0) | 2015.11.02 |
- Total
- Today
- Yesterday
- 아이폰
- 앱스토어
- 구글
- 안드로이드
- Apple
- 대학생
- 소프트웨어
- 스마트폰
- JavaScript
- 네이버
- 트위터
- 게임
- 벤처
- 아이디어
- 창업
- php
- 자바스크립트
- 경진대회
- 앱
- 웹표준
- 모바일
- CSS
- 공모전
- 애플
- AWS
- 어플리케이션
- iPhone
- android
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |