WebView File Upload Over Kitkat

Android over kitkat doesn’t work WebChromeClient openFileChoose

  1. Input type file click event call android method that start file select (ex : gallery)
  2. Get Selected file path
  3. Upload file to server return file path that uploaded server
  4. Submit Form with File Upload Sucess message (ex : server uploaded path)

Call Android Method openFileChoose JavascriptInterface

JavascriptInterface.java

public class JavaScriptInterface {
    private final static String TAG = "JavaScriptInterface";
    private Handler mHandler;

    @JavascriptInterface
    public void openFileChoose() {
        Logger.debug(this, "openFileChoose");
        Message msg = new Message();
        msg.what = HandlerOwner.MSG_FILE_CHOOSE;
        mHandler.sendMessage(msg);
    }

    @JavascriptInterface
    public void uploadFileCall() {
        Logger.debug(this, "uploadFileCall");
        Message msg = new Message();
        msg.what = HandlerOwner.MSG_UPLOAD_FILE_CALL;
        mHandler.sendMessage(msg);
    }


}

Receive JavascriptInterface Message on Activity

WebActivity.java

@EActivity(R.layout.activity_web)
public class WebActivity extends BaseActivity implements View.OnClickListener, HandlerOwner, TaskObserver{

    @ViewById(R.id.webView)
    WebView webView;

    File uploadFile;

    private JavaScriptInterface jsInterface;
    private Handler mHandler;
    private String title, webViewUrl;
    private WebChromeClient webChromeClient;
    private WebClient webClient;

    @AfterViews
    void initView() {
        webClient = new WebClient(this);
        webView.setWebViewClient(webClient);
        webChromeClient = new WebChromeClient(this);
        webView.setWebChromeClient(webChromeClient);
        WebSettings set = webView.getSettings();
        set.setJavaScriptEnabled(true);
        set.setBuiltInZoomControls(true);
        set.setDomStorageEnabled(true);

        Intent intent = getIntent();
        title = intent.getStringExtra("title");
        webViewUrl = intent.getStringExtra("url");

        if(!webViewUrl.equals("")) {
            webView.loadUrl(webViewUrl);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web);
        Logger.debug(this, ON_CREATE_START);

        Logger.debug(this, ON_CREATE_END);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Logger.debug(this, ON_RESUME_START);

        if(mHandler == null) {
            mHandler = new Handler(this);
        }

        jsInterface = new JavaScriptInterface(mHandler);
        webView.addJavascriptInterface(jsInterface, "Android");

        Logger.debug(this, ON_RESUME_END);
    }
    @Override
    protected void onPause() {
        super.onPause();
        Logger.debug(this, ON_PAUSE_START);

        Logger.debug(this, ON_PAUSE_END);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Logger.debug(this, "keyCode : "+keyCode);
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                if(webView.canGoBack()) {
                    webView.goBack();
                    return true;
                }
        }
        return super.onKeyDown(keyCode, event);
    }
    
    @Override
    public void onMessage(Message message) {
        Logger.debug(this, ON_MESSAGE_START);
        Logger.debug(this, "message.what : "+ message.what);
        switch (message.what) {
            case MSG_FILE_CHOOSE:
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                startActivityForResult(Intent.createChooser(i, "File Chooser"), WebChromeClient.FILECHOOSER_RESULTCODE);
                break;
            case MSG_UPLOAD_FILE_CALL:
                FileUploadAsyncTask fileUploadAsyncTask = new FileUploadAsyncTask(this, null);
                fileUploadAsyncTask.execute(uploadFile.getAbsolutePath());
                break;
        }

        Logger.debug(this, ON_MESSAGE_END);
    }
    //Select File onActivityResult getFilePath
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
//        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode== WebChromeClient.FILECHOOSER_RESULTCODE)
        {
            //if (null == webChromeClient.getmUploadMessage()) return;
            if(resultCode == RESULT_OK) {
                Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
                Logger.debug(this, "image Uri : " +result.toString());
                Logger.debug(this, "file name : " +uriToFile(result).getName());
                webView.loadUrl("javascript:getFileName('"+uriToFile(result).getName()+"')");
                uploadFile = uriToFile(result);
            }

        }
    }

    @TargetApi(19)
    private File uriToFile ( Uri uri ) {

        String filePath = "";
        if ( uri.getPath().contains(":") ) {
            String wholeID = DocumentsContract.getDocumentId(uri);
            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];
            String[] column = { MediaStore.Images.Media.DATA };
            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";
            Cursor cursor = this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null);

            int columnIndex = cursor.getColumnIndex(column[0]);
            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();

        } else {
            String id = uri.getLastPathSegment();
            final String[] imageColumns = {MediaStore.Images.Media.DATA };
            final String imageOrderBy = null;

            String selectedImagePath = "path";
            String scheme = uri.getScheme();
            if ( scheme.equalsIgnoreCase("content") ) {
                Cursor imageCursor = this.getContentResolver().query(uri, imageColumns, null, null, null);

                if (imageCursor.moveToFirst()) {
                    filePath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }
            } else {
                filePath = uri.getPath();
            }
        }
        File file = new File( filePath );
        return file;
    }
    @Override
    public void update(Class cls, Object returnObj) {
        Logger.debug(this, TASK_OBSERVER_UPDATE_START);
        Logger.debug(this, cls.getSimpleName());
        if(cls.equals(FileUploadAsyncTask.class)) {
            FileUploadRes uploadRes = (FileUploadRes)returnObj;
            if(uploadRes != null) {
                String atchFilePth = uploadRes.getAtchFilePth();
                String atchFileMg = uploadRes.getAtchFileMg();
                Logger.debug(this, "atchFilePth : "+ atchFilePth+ " / atchFileMg : "+atchFileMg);
                // Receive AsynTaskResult Ok
                webView.loadUrl("javascript:getUploadFilePath('"+atchFilePth+"', '"+atchFileMg+"')");
            }

        }
        Logger.debug(this, TASK_OBSERVER_UPDATE_END);
    }

    public class WebClient extends WebViewClient {

        Context context;

        public WebClient(Context context) {
            this.context = context;
        }

        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Logger.debug(WebActivity.this, "shouldOverrideUrlLoading : "+ url);
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            Logger.debug(this, "onPageFinished : "+url);
        }
    }
}

Get File Upload to Server

FileUploadAsyncTask.java

public class FileUploadAsyncTask extends BaseAsyncTask implements UrlConstant {
    private static AsyncTaskResult asyncTaskResult = null;

    public FileUploadAsyncTask(TaskObserver caller, String progressMsg) {
        super(caller, progressMsg);
    }

    @Override
    protected AsyncTaskResult doInBackground(Object... params) {
        try {
            String path = (String)params[0];
            AsyncHttpPost post = new AsyncHttpPost(HTTP_URL+CONTEXT+FILE_UPLOAD);
            MultipartFormDataBody body = new MultipartFormDataBody();
            // parameters are name, value
            body.addFilePart("atchFile", new File(path));
            post.setBody(body);

            AsyncHttpClient.getDefaultInstance().executeJSONObject(post, new AsyncHttpClient.JSONObjectCallback(){
                @Override
                public void onCompleted(Exception e, AsyncHttpResponse asyncHttpResponse, JSONObject result) {
                    if (e != null) {
                        e.printStackTrace();
                        asyncTaskResult = new AsyncTaskResult(AsyncTaskResultType.RESULT_TIMEOUT, e);
                        return;
                    }
                    if (result != null) {
                        try {
                            Logger.debug(this, "result\n" + result.toString());
                            Gson gsonResult = new Gson();
                            FileUploadRes fileUploadRes = gsonResult.fromJson(result.toString(), FileUploadRes.class);
                            asyncTaskResult = new AsyncTaskResult(AsyncTaskResultType.RESULT_SUCCESS, fileUploadRes);
                        } catch (Exception e1) {
                            e1.printStackTrace();
                            asyncTaskResult = new AsyncTaskResult(AsyncTaskResultType.RESULT_FAIL);
                        }

                    } else {
                        asyncTaskResult = new AsyncTaskResult(AsyncTaskResultType.RESULT_FAIL);
                    }
                }
            });
            while (asyncTaskResult == null) {
                Thread.sleep(100);
            }

        } catch (Exception e) {
            Logger.error(this, e.getLocalizedMessage());
            asyncTaskResult = new AsyncTaskResult(AsyncTaskResultType.RESULT_FAIL, e);
        }
        return asyncTaskResult;
    }
}

File upload Sucess call webview javascript method upload success

    // Receive AsynTaskResult Ok
    webView.loadUrl("javascript:getUploadFilePath('"+atchFilePth+"', '"+atchFileMg+"')");

Submit Form with Server UploadFilePath that after AsyncTask success

Conclusion

Android

  1. Call Image Pick Activity
  2. Get File Url
  3. File upload to server

Server

  1. input type file click call andorid javascript method that file pick
  2. fill the file path input type file
  3. Receive File upload
  4. submit with get uploaded file path

Reference
Android WebView File Upload
File Upload in WebView (Android)
[Android, Hybrid]openFileChooser 킷캣에서 동작하지 않는 문제( openFileChooser Kitkat bug )


Comments

Leave a Reply