简体   繁体   English

Android WebView文件上传

[英]Android WebView File Upload

I am developing an Android app. 我正在开发一款Android应用。 Basically it is a WebView and a progressBar. 基本上它是一个WebView和一个progressBar。 Facebook's mobile site (m.facebook.com) is loaded into the WebView . Facebook的移动网站(m.facebook.com)被加载到WebView

When I click on the Choose File button to upload an image, nothing happens. 当我单击“选择文件”按钮上传图像时,没有任何反应。 I have tried ALL of the solutions and none of them work. 我已经尝试了所有解决方案,但没有一个能够正常工作。 I am testing on a Galaxy Note (GT-N7000) running 4.0.3. 我正在测试运行4.0.3的Galaxy Note(GT-N7000)。 My minimum SDK version is version 8. 我的最低SDK版本是版本8。

我的应用程序
(source: istyla.com ) (来源: istyla.com

Here is my code for more info... 这是我的代码了解更多信息......

public class IStyla extends Activity {
    private ValueCallback<Uri> mUploadMessage;
    private final static int FILECHOOSER_RESULTCODE = 1;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage)
                return;
            Uri result = intent == null || resultCode != RESULT_OK ? null
                    : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;

        }
    }
    private class MyWebChromeClient extends WebChromeClient {
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            mUploadMessage = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("image/*");
            IStyla.this.startActivityForResult(Intent.createChooser(i, "Image Browser"), FILECHOOSER_RESULTCODE);
        }

        @Override
        public boolean onJsAlert(WebView view, String url, String message,final JsResult result) {
            //handle Alert event, here we are showing AlertDialog
            new AlertDialog.Builder(IStyla.this)
                .setTitle("JavaScript Alert !")
                .setMessage(message)
                .setPositiveButton(android.R.string.ok,
                    new AlertDialog.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do your stuff
                            result.confirm();
                        }
                    }).setCancelable(false).create().show();
            return true;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_istyla);
        WebView webView = (WebView) findViewById(R.id.webView1);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webView.setWebChromeClient(new MyWebChromeClient(){
            public void onProgressChanged(WebView view, int progress) {
                // Activities and WebViews measure progress with different scales.
                // The progress meter will automatically disappear when we reach 100%
                ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar1);
                if(progress < 100 && progressBar.getVisibility() == ProgressBar.GONE){
                    progressBar.setVisibility(ProgressBar.VISIBLE);
                }
                progressBar.setProgress(progress);
                if(progress == 100) {
                    progressBar.setVisibility(ProgressBar.GONE);
                }
            }
            public void openFileChooser(ValueCallback<Uri> uploadMsg) {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                IStyla.this.startActivityForResult(Intent.createChooser(i, "Image Browser"), FILECHOOSER_RESULTCODE);
            }
        });
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar1);
                progressBar.setVisibility(ProgressBar.VISIBLE);
                return true;
            }

        });
        webView.loadUrl("https://m.facebook.com");

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK){
            if(((WebView)findViewById(R.id.webView1)).canGoBack()){
                ((WebView)findViewById(R.id.webView1)).goBack();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_istyla, menu);
        return true;
    }

}

Thanks 谢谢

This is how i am using in my app 这就是我在我的应用程序中使用的方式

 private class MyWebChromeClient extends WebChromeClient {
    //The undocumented magic method override
    //Eclipse will swear at you if you try to put @Override here


    // For Android 3.0+
    public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
        mUploadMessage = uploadMsg;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
    }

    //For Android 4.1+ only
    protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUploadMessage = uploadMsg;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
    }

    protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
        mUploadMessage = uploadMsg;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE);
    }

    // For Lollipop 5.0+ Devices
    public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
        if (uploadMessage != null) {
            uploadMessage.onReceiveValue(null);
            uploadMessage = null;
        }

        uploadMessage = filePathCallback;
        Intent intent = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            intent = fileChooserParams.createIntent();
        }
        try {
            startActivityForResult(intent, REQUEST_SELECT_FILE);
        } catch (ActivityNotFoundException e) {
            uploadMessage = null;
            Toast.makeText(getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
            return false;
        }
        return true;
    }

Mike Olivier's reference shared by Fr33dan is important. Fr33dan分享的Mike Olivier的参考很重要。 I am sharing what worked for me under situation quite akin yours. 我正在分享在我的情况下对我有用的东西。

wv.setWebChromeClient(new WebChromeClient()  {

// For Android 3.0+
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {  
mUploadMessage = uploadMsg;  
Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
i.addCategory(Intent.CATEGORY_OPENABLE);  
i.setType("image/*");  
MainActivity.this.startActivityForResult( Intent.createChooser( i, getString(R.string.fileselect) ), MainActivity.FILECHOOSER_RESULTCODE ); 
}

// For Android < 3.0
public void openFileChooser( ValueCallback<Uri> uploadMsg ) {
openFileChooser( uploadMsg, "" );
}


// For Android > 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
openFileChooser( uploadMsg, "" );
}
});

NOTE: I found this somewhere in stack overflow and m0s' blog . 注意:我在堆栈溢出和m0s的博客中找到了这个地方。

Also, Ignore lint warnings. 另外,忽略lint警告。 This one works pretty well for API 8 and above. 这个适用于API 8及更高版本。

Given the high number of votes I'm guessing no one has noticed the 3rd comment (from David Esteves ) contains a link with to answer to this question. 鉴于投票数量很高,我猜测没有人注意到第3条评论(来自David Esteves )包含了回答这个问题的链接。

Michel Olivier said: 米歇尔奥利维尔说:

This solution also works for Honeycomb and Ice Cream Sandwich. 该解决方案也适用于Honeycomb和Ice Cream Sandwich。 Seems like Google introduced a cool new feature (accept attribute) and forgot to to implement an overload for backwards compatibility. 似乎谷歌推出了一个很酷的新功能(接受属性),忘了实现过载以实现向后兼容。

So you just need to add a openFileChooser overload to your MyWebChromeClient class that accepts the string parameter and then call the one that does not: 所以你只需要在接受字符串参数的MyWebChromeClient类中添加一个openFileChooser重载,然后调用不会:

public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) 
{  
    this.openFileChooser(uploadMsg);
}

Doing this I was able to make your code run as intended. 这样做我能够使您的代码按预期运行。

This code will help to solve the issue 此代码将有助于解决此问题

Just update the MainActivity.Java file with the bellow code 只需使用下面的代码更新MainActivity.Java文件即可

public class MainActivity extends Activity{
    private WebView mWebview ;
    private ValueCallback<Uri> mUploadMessage;
    public ValueCallback<Uri[]> uploadMessage;
    public static final int REQUEST_SELECT_FILE = 100;
    private final static int FILECHOOSER_RESULTCODE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        mWebview  = (WebView) findViewById(R.id.help_webview);
        WebSettings webSettings = mWebview.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setUseWideViewPort(true);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setAllowFileAccess(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setPluginState(WebSettings.PluginState.ON);
        webSettings.setSupportZoom(true);
        webSettings.setAllowContentAccess(true);



        final Activity activity = this;
        mWebview.setWebViewClient(new WebViewClient() {
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                Toast.makeText(activity, description, Toast.LENGTH_SHORT).show();
            }
        });

        mWebview .loadUrl("http://www.google.com");

        String permission = Manifest.permission.CAMERA;
        int grant = ContextCompat.checkSelfPermission(this, permission);
        if (grant != PackageManager.PERMISSION_GRANTED) {
            String[] permission_list = new String[1];
            permission_list[0] = permission;
            ActivityCompat.requestPermissions(this, permission_list, 1);
        }


        mWebview.setWebChromeClient(new WebChromeClient()
        {
            // For 3.0+ Devices (Start)
            // onActivityResult attached before constructor
            protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
            {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
            }


            // For Lollipop 5.0+ Devices
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
            {
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(null);
                    uploadMessage = null;
                }

                uploadMessage = filePathCallback;

                Intent intent = fileChooserParams.createIntent();
                try
                {
                    startActivityForResult(intent, REQUEST_SELECT_FILE);
                } catch (ActivityNotFoundException e)
                {
                    uploadMessage = null;
                    Toast.makeText(MainActivity.this.getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
                    return false;
                }
                return true;
            }

            //For Android 4.1 only
            protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
            {
                mUploadMessage = uploadMsg;
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.setType("image/*");
                startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
            }

            protected void openFileChooser(ValueCallback<Uri> uploadMsg)
            {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
            }
        });



    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent)
    {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            if (requestCode == REQUEST_SELECT_FILE)
            {
                if (uploadMessage == null)
                    return;
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
                uploadMessage = null;
            }
        }
        else if (requestCode == FILECHOOSER_RESULTCODE)
        {
            if (null == mUploadMessage)
                return;
            // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
            // Use RESULT_OK only if you're implementing WebView inside an Activity
            Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
        else
            Toast.makeText(MainActivity.this.getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
    }

Make sure to enable the permission in the AndroidManifest.xml update the following lines 确保在AndroidManifest.xml中启用权限更新以下行

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

It worked for me try with this code. 它适用于我尝试使用此代码。

When invoking AlertDialog in WebChromeClient.OpenFileChooser, you need to notify webchrome that no selection was done in case of back button. 在WebChromeClient.OpenFileChooser中调用AlertDialog时,您需要通知webchrome在后退按钮的情况下没有选择。 Since Back button can be pressed in you dialog, you have to handle OnCancel of the dialog and tell WebChrome that selection was finished. 由于可以在对话框中按下“返回”按钮,因此必须处理对话框的OnCancel并告知WebChrome选择已完成。

eg: 例如:

private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
private final static int CAMERA_RESULTCODE = 2;

...

    webView.setWebChromeClient(new WebChromeClient() {
      public boolean onConsoleMessage(ConsoleMessage cm) {
        Log.d("MyApplication", cm.message() + " -- From line "
                             + cm.lineNumber() + " of "
                             + cm.sourceId() );
        return true;
      }

      public void onExceededDatabaseQuota(String url, String
            databaseIdentifier, long currentQuota, long estimatedSize, long
            totalUsedQuota, QuotaUpdater quotaUpdater) {
                            quotaUpdater.updateQuota(estimatedSize+65536);
            } 

     @SuppressWarnings("unused")
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {
            this.openFileChooser(uploadMsg);
         }

     @SuppressWarnings("unused")
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {
        this.openFileChooser(uploadMsg);
     }

     public void openFileChooser(ValueCallback<Uri> uploadMsg) {

         mUploadMessage = uploadMsg;
        PesScreen.this.openImageIntent();
     }
    });        

... ...

private void openImageIntent() {

final File root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); //file storage


    root.mkdirs();
    int nCnt = 1;
    if ( root.listFiles() != null )
        nCnt = root.listFiles().length;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
    final String fname =  String.format("/dest-%s-%d.jpg", sdf.format(Calendar.getInstance().getTime()), nCnt);

    final File sdImageMainDirectory = new File(root.getAbsolutePath() + fname);
    outputFileUri = Uri.fromFile(sdImageMainDirectory);
//selection Photo/Gallery dialog
    AlertDialog.Builder alert = new AlertDialog.Builder(this);

    alert.setTitle("Select source");

    final CharSequence[] items = {"Photo", "Gallery"};
    alert.setItems(items, new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int whichButton) {

            dialog.dismiss();
            if( whichButton == 0)
            {
                Intent chooserIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                chooserIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
                startActivityForResult(chooserIntent, CAMERA_RESULTCODE);
            }
            if( whichButton == 1)
            {
                Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
                chooserIntent.setType("image/*");
                startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
            }
      }
    });
    alert.setOnCancelListener(new DialogInterface.OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {

        //here we have to handle BACK button/cancel 
            if ( mUploadMessage!= null ){
                mUploadMessage.onReceiveValue(null);
            }
            mUploadMessage = null;
            dialog.dismiss();
        }
    });
    alert.create().show();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM