출처 : http://it-archives.com/222114870620/  (흑곰의 유익한 블로그 2호점)

아이폰(iOS) 하이브리드 앱에서는 <input type=”file”> 을 사용하면 해당 요소를 클릭 시 파일선택 창(FileChooser)이 잘 뜨지만, 안드로이드 웹뷰에서는 <input type=”file”> 요소를 클릭해도 아무 반응이 없다.

안드로이드 하이브리드앱에서 파일을 선택하는 기능은 아래와 같이 구현 가능하다.

1. mFilePathCallback 변수를 전역변수로 선언한다.

webView 를 사용할 Activity 클래스(또는 Activity 를 상속받은 클래스) 에 선언하면 된다.

    // 안드로이드 웹뷰에서 파일 첨부하기
    ValueCallback mFilePathCallback = null;

2. WebChromeClient 클래스의 onShowFileChooser 메서드를 오버라이딩해서 아래와 같이 작성한다.

파일 n개 선택(파일 여러개 선택, 파일 다중선택) 하려면 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); 코드를 포함시키자.

    webView.setWebChromeClient(new WebChromeClient() {
        // 안드로이드 웹뷰에서 파일 첨부하기
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
            mFilePathCallback = filePathCallback;

            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType(“image/*”);

            // 파일 n개 선택 가능하도록 처리
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

            startActivityForResult(intent, 0);
            return true;
        }
    });

만약 WebChromeClient 를 상속받아 별개의 자바파일로 구현했다면(ex : public class OOOWebChromeClient extends WebChromeClient {}), startActivityForResult 메서드를 곧바로 사용할 수 없을 것이다.

이 경우 WebChromeClient 생성자에서 activity 를 받아 thisActivity 라는 멤버변수에 저장해놓으면 thisActivity.startActivityForResult(intent, 0); 식으로 사용할 수 있다.

public class OOOWebChromeClient extends WebChromeClient {
    private final Activity thisActivity;

    public OOOWebChromeClient(Activity thisActivity) {
        super();
        this.thisActivity = thisActivity;
    }

    (중략)

}   

3. mFilePathCallback 변수가 선언된 클래스, 다시 말해서 Activify 클래스(또는 Activity를 상속한 클래스) 하단에 아래와 같이 작성한다.

참고로 파일을 n개 선택(여러개 선택, 다중선택)한 경우 data.getClipData() 값이 not null이며, 파일을 1개 선택한 경우 data.getData() 값이 not null이다.

    // 안드로이드 웹뷰에서 파일 첨부하기
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        Log.e(“resultCode:: “, String.valueOf(resultCode));
        if (requestCode == 0 && resultCode == Activity.RESULT_OK) {

            // 파일 n개 선택한 경우
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && data != null && data.getClipData() != null && data.getClipData().getItemCount() > 0) {
                int count = data.getClipData().getItemCount();

                Uri[] uriArr = new Uri[count];
                for (int i=0; i<count; i++) {
                    uriArr[i] = data.getClipData().getItemAt(i).getUri();
                }

                mFilePathCallback.onReceiveValue(uriArr);

            } else if (data != null && data.getData() != null) {
                // 파일 1개 선택한 경우
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    mFilePathCallback.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                } else {
                    mFilePathCallback.onReceiveValue(new Uri[]{data.getData()});
                }
            }

            mFilePathCallback = null;

        } else {
            mFilePathCallback.onReceiveValue(null);
        }
    }

만약 WebChromeClient 를 상속받아 별개의 자바파일로 구현했다면(ex : public class OOOWebChromeClient extends WebChromeClient {}), mFilePathCallback 변수를 사용할 수 없을 것이다. OOOWebChromeClien 클래스 내에 mFilePathCallback 의 getter, setter 메서드를 만들어서 접근하도록 하자.

Posted by 꼬장e
,