【问题标题】:Android WebView File UploadAndroid WebView 文件上传
【发布时间】:2012-07-28 06:37:46
【问题描述】:

我正在开发一个 Android 应用程序。基本上它是一个WebView 和一个progressBar。 Facebook 的移动网站 (m.facebook.com) 加载到 WebView

当我单击“选择文件”按钮上传图像时,没有任何反应。我已经尝试了所有解决方案,但没有一个有效。我正在运行 4.0.3 的 Galaxy Note (GT-N7000) 上进行测试。我的最低 SDK 版本是 8 版。


(来源:istyla.com

这是我的代码以获取更多信息...

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;
    }

}

谢谢

【问题讨论】:

标签: java android file-upload android-webview


【解决方案1】:

这就是我在我的应用中使用的方式

 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;
    }

【讨论】:

  • 对我来说很好。但是当我从棉花糖设备中的文档选择器中选择图库时,它不会获取文件。
  • 什么是uploadMessage?什么是 REQUEST_SELECT_FILE?
  • uploadMessage 是 ValueCallback(检查问题代码),REQUEST_SELECT_FILE 是任何整数,用于跟踪 onActivityResult()。
  • 只需要在 onActivityResult Uri[] uris = new Uri[1]; uris[0] = 结果; uploadMessage.onReceiveValue(uris);
  • FileChooserParams 已经 21 岁以上,还有onShowFileChooser
【解决方案2】:

Fr33dan 共享的Mike Olivier's reference 很重要。我正在分享在与您的情况非常相似的情况下对我有用的方法。

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, "" );
}
});

注意:我在堆栈溢出和m0s' blog 的某个地方发现了这个。

另外,忽略 lint 警告。这个适用于 API 8 及更高版本。

【讨论】:

  • 很多用户还在使用android 3.0及以下。甚至,我在 SO 社区发现了这个。 :)
  • 即使我实现了这个功能也没有发生任何事情。而且它不是递归函数调用吗?
【解决方案3】:

考虑到高票数,我猜没有人注意到第三条评论(来自David Esteves)包含a link with to answer to this question.

Michel Olivier说:

此解决方案也适用于蜂窝和冰淇淋三明治。似乎 像谷歌推出了一个很酷的新功能(接受属性)和 忘记实现向后兼容的重载。

所以你只需要添加一个openFileChooser 重载到你的MyWebChromeClient 类接受字符串参数,然后调用不接受的那个:

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

这样做我能够让您的代码按预期运行。

【讨论】:

    【解决方案4】:

    在 WebChromeClient.OpenFileChooser 中调用 AlertDialog 时,您需要通知 webchrome 在返回按钮的情况下未进行任何选择。 由于可以在对话框中按下后退按钮,因此您必须处理对话框的 OnCancel 并告诉 WebChrome 选择已完成。

    例如:

    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();
    

    【讨论】:

      【解决方案5】:

      此代码将有助于解决问题

      只需使用以下代码更新 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();
          }
      

      确保启用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" />
      

      尝试使用此代码对我有用。

      【讨论】:

      • 这可行,但它只允许我上传视频,它也没有调出相机选项,而是打开了文件选择器。
      • 那么,如果你清楚地告诉它,你到底需要什么,它会有所帮助@TheLearner
      • 我需要通过 webview 将图像和视频上传到网站。如果用户决定使用他们的相机来上传他们拍摄的照片,并且如果他们选择了一个图像/视频以将其上传到 webview,我希望它。
      • 对我来说另一个主要问题是,返回图像的代码在哪里?我很难找到那个部分。谢谢。
      • 用户可以在此代码的帮助下上传照片和视频以及其他文件,它工作正常,请告诉我您的应用程序的 apk 版本,因为它改变我在这里给出的代码,它适用于目标 Marshmallow 版本,并且在运行应用程序时它要求用户允许相机和存储,所以我已经上传了文件@TheLearner
      猜你喜欢
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      • 2021-12-10
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 2013-01-22
      • 1970-01-01
      相关资源
      最近更新 更多