网页通过webview调用Android的图片或文件选择

原文                   http://www.cnblogs.com/qinxianyuzou/p/3490243.html

前段时间因为客户需求,做一个客户端结合web微网站的应用。其中,这个应用设计到了要修改头像,但是这个页面却是在微网站上实现的,意味着网站要调用到Android的打开文件的方法,那么这个通过webview是怎么实现的呢?

经过跟服务器的同事讨论发现,方法都是跟pc上是一样的,都是调用一个叫input type=file的属性,于是我就开始找,webview是怎么响应这个属性的了。

于是翻网站找到资料,不难查到,想要适用php上调用打开文件的方法,webview就要重写一个名为openFileChooser的方法。

但是这个方法的使用却不简单,这个方法是要调用webview的setWebChromeClient方法,然后重写一个WebChromeClient类。来到这一步,相信有点开发经验的同行都不难解决。问题的关键就在于,当你重写WebChromeClient这个类的时候会发现,根本就没有openFileChooser这个方法,那要怎么重写呢?是不是意味着这个方法其实行不通?于是再次翻查资料,发现原来这个方法居然是隐藏方法,并不不存在显性的继承重写关系。

最后,我发现要使用这个方法,还得自己继承WebChromeClient这个类把openFileChooser(ValueCallback<Uri> uploadFile)这个方法给写出来,代码如下:

abstract class TestWebChromeClient extends WebChromeClient
{

  private WebChromeClient mWrappedClient;

  protected TestWebChromeClient(WebChromeClient wrappedClient)
  {
    mWrappedClient = wrappedClient;
  }

  /** {@inheritDoc} */
  @Override
  public void onProgressChanged(WebView view, int newProgress)
  {
    mWrappedClient.onProgressChanged(view, newProgress);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedTitle(WebView view, String title)
  {
    mWrappedClient.onReceivedTitle(view, title);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedIcon(WebView view, Bitmap icon)
  {
    mWrappedClient.onReceivedIcon(view, icon);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)
  {
    mWrappedClient.onReceivedTouchIconUrl(view, url, precomposed);
  }

  /** {@inheritDoc} */
  @Override
  public void onShowCustomView(View view, CustomViewCallback callback)
  {
    mWrappedClient.onShowCustomView(view, callback);
  }

  /** {@inheritDoc} */
  @Override
  public void onHideCustomView()
  {
    mWrappedClient.onHideCustomView();
  }

  /** {@inheritDoc} */
  @Override
  public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
      Message resultMsg)
  {
    return mWrappedClient.onCreateWindow(view, dialog, userGesture, resultMsg);
  }

  /** {@inheritDoc} */
  @Override
  public void onRequestFocus(WebView view)
  {
    mWrappedClient.onRequestFocus(view);
  }

  /** {@inheritDoc} */
  @Override
  public void onCloseWindow(WebView window)
  {
    mWrappedClient.onCloseWindow(window);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsAlert(WebView view, String url, String message, JsResult result)
  {
    return mWrappedClient.onJsAlert(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsConfirm(WebView view, String url, String message, JsResult result)
  {
    return mWrappedClient.onJsConfirm(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsPrompt(WebView view, String url, String message,
      String defaultValue, JsPromptResult result)
  {
    return mWrappedClient.onJsPrompt(view, url, message, defaultValue, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsBeforeUnload(WebView view, String url, String message,
      JsResult result)
  {
    return mWrappedClient.onJsBeforeUnload(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public void onExceededDatabaseQuota(String url, String databaseIdentifier,
      long currentQuota, long estimatedSize, long totalUsedQuota,
      WebStorage.QuotaUpdater quotaUpdater)
  {
    mWrappedClient.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota,
        estimatedSize, totalUsedQuota, quotaUpdater);
  }

  /** {@inheritDoc} */
  @Override
  public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
      WebStorage.QuotaUpdater quotaUpdater)
  {
    mWrappedClient
        .onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota, quotaUpdater);
  }

  /** {@inheritDoc} */
  @Override
  public void onGeolocationPermissionsShowPrompt(String origin,
      GeolocationPermissions.Callback callback)
  {
    mWrappedClient.onGeolocationPermissionsShowPrompt(origin, callback);
  }

  /** {@inheritDoc} */
  @Override
  public void onGeolocationPermissionsHidePrompt()
  {
    mWrappedClient.onGeolocationPermissionsHidePrompt();
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsTimeout()
  {
    return mWrappedClient.onJsTimeout();
  }

  /** {@inheritDoc} */
  @Override
  @Deprecated
  public void onConsoleMessage(String message, int lineNumber, String sourceID)
  {
    mWrappedClient.onConsoleMessage(message, lineNumber, sourceID);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onConsoleMessage(ConsoleMessage consoleMessage)
  {
    return mWrappedClient.onConsoleMessage(consoleMessage);
  }

  /** {@inheritDoc} */
  @Override
  public Bitmap getDefaultVideoPoster()
  {
    return mWrappedClient.getDefaultVideoPoster();
  }

  /** {@inheritDoc} */
  @Override
  public View getVideoLoadingProgressView()
  {
    return mWrappedClient.getVideoLoadingProgressView();
  }

  /** {@inheritDoc} */
  @Override
  public void getVisitedHistory(ValueCallback<String[]> callback)
  {
    mWrappedClient.getVisitedHistory(callback);
  }

  /** {@inheritDoc} */

  public void openFileChooser(ValueCallback<Uri> uploadFile)
  {
    ((TestWebChromeClient) mWrappedClient).openFileChooser(uploadFile);
  }

}
 

以上代码我是在eoe上发现的,并不是我自己参详发现的哈。但是原作是谁我就不知道了,因为这段代码你只要百度一下openFileChooser这个方法你就能找到。

当你这样写好,然后就是去设置WebChromeClient的时候了。设置方法如下:

mContentView.web_main_web.setWebChromeClient(new TestWebChromeClient(
        new WebChromeClient())
    {
      public void openFileChooser(ValueCallback<Uri> uploadFile)
      {
         if (mUploadMessage != null)
         return;
         mUploadMessage = uploadFile;

                    //自己写你的调用图片方法,我这里是封装了调用图片的方法的
                    //关键点在于这个mUploadMessage参数,获取到图片以后传给这个参数回去就可以了。
                    //具体用法百度一下就有。
                    Select_Activity.start(mContext, mUploadMessage,indexUrlString,FILE_SELECTED);
      }

    });

 当你设置完后,这个时候你就该兴高采烈地去测试了。

于是,你有可能会兴高采烈地发现,不行!!完全没有反应!

是不是开始怀疑这个方法是坑人的?是不是在努力骂撸主?来来来,别生气,让我告诉你真相。

我告诉你哦,这个方法其实一点都不吭人,真的可以啊,不过~这是在3.0以前的sdk上有效...但是现在的主流Android机基本都是4.0以上了,哪里还有3.0以前的系统?

于是你又开始了新的一轮骂娘,为什么我会知道?因为我那个时候也是这个反应!

那时候我努力地翻资料,把百度、eoe、CSDN、德问、博客园、安卓巴士、DEVDIV都翻烂了,终于找到了原因,原来泥煤的3.0的要多加一个参数才能生效!

于是我傻乎乎的仿照人家重写的openFileChooser方法,给TestWebChromeClient这个类添加了一个openFileChooser(ValueCallback<Uri> uploadFile, String acceptType)方法。(具体这个acceptType参数有什么用,我还不怎么清楚,有知道的大神麻烦告知一下哈)在webview的setWebChromeClient方法里也添加了一个对应调用方法。

于是新一轮测试又开始了。

终于,你又一次兴高采烈地骂娘了,泥煤的还是不行啊!(po主:喂!别打头,把我打傻了以后就不能分享技术了!)

于是,我终于相信了国内搜索引擎和论坛的不靠谱,我投靠了谷歌和stackoverflow。

说实话,po主的英文很烂,烂得掉渣了,只有小学5年级的水准(po主那个时候是四年纪开始学的英语)所以不到逼不得已都不想投靠外国网站,实在是看不到,这搜索不来啊!

我找了足足一天得谷歌,最后通过谷歌找到了stackoverflow上有这个相同的问题(我这英文的水平只能通过谷歌使用了,捂脸)

人家大神解答到,原来尼玛的4.0以后的版本又多了一个参数于是乎,再加一个openFileChooser(ValueCallback<Uri> uploadFile, String acceptType,String capture)方法就可以了。

下面我贴上TestWebChromeClient的完整代码。

abstract class TestWebChromeClient extends WebChromeClient
{

  private WebChromeClient mWrappedClient;

  protected TestWebChromeClient(WebChromeClient wrappedClient)
  {
    mWrappedClient = wrappedClient;
  }

  /** {@inheritDoc} */
  @Override
  public void onProgressChanged(WebView view, int newProgress)
  {
    mWrappedClient.onProgressChanged(view, newProgress);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedTitle(WebView view, String title)
  {
    mWrappedClient.onReceivedTitle(view, title);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedIcon(WebView view, Bitmap icon)
  {
    mWrappedClient.onReceivedIcon(view, icon);
  }

  /** {@inheritDoc} */
  @Override
  public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)
  {
    mWrappedClient.onReceivedTouchIconUrl(view, url, precomposed);
  }

  /** {@inheritDoc} */
  @Override
  public void onShowCustomView(View view, CustomViewCallback callback)
  {
    mWrappedClient.onShowCustomView(view, callback);
  }

  /** {@inheritDoc} */
  @Override
  public void onHideCustomView()
  {
    mWrappedClient.onHideCustomView();
  }

  /** {@inheritDoc} */
  @Override
  public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
      Message resultMsg)
  {
    return mWrappedClient.onCreateWindow(view, dialog, userGesture, resultMsg);
  }

  /** {@inheritDoc} */
  @Override
  public void onRequestFocus(WebView view)
  {
    mWrappedClient.onRequestFocus(view);
  }

  /** {@inheritDoc} */
  @Override
  public void onCloseWindow(WebView window)
  {
    mWrappedClient.onCloseWindow(window);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsAlert(WebView view, String url, String message, JsResult result)
  {
    return mWrappedClient.onJsAlert(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsConfirm(WebView view, String url, String message, JsResult result)
  {
    return mWrappedClient.onJsConfirm(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsPrompt(WebView view, String url, String message,
      String defaultValue, JsPromptResult result)
  {
    return mWrappedClient.onJsPrompt(view, url, message, defaultValue, result);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsBeforeUnload(WebView view, String url, String message,
      JsResult result)
  {
    return mWrappedClient.onJsBeforeUnload(view, url, message, result);
  }

  /** {@inheritDoc} */
  @Override
  public void onExceededDatabaseQuota(String url, String databaseIdentifier,
      long currentQuota, long estimatedSize, long totalUsedQuota,
      WebStorage.QuotaUpdater quotaUpdater)
  {
    mWrappedClient.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota,
        estimatedSize, totalUsedQuota, quotaUpdater);
  }

  /** {@inheritDoc} */
  @Override
  public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
      WebStorage.QuotaUpdater quotaUpdater)
  {
    mWrappedClient
        .onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota, quotaUpdater);
  }

  /** {@inheritDoc} */
  @Override
  public void onGeolocationPermissionsShowPrompt(String origin,
      GeolocationPermissions.Callback callback)
  {
    mWrappedClient.onGeolocationPermissionsShowPrompt(origin, callback);
  }

  /** {@inheritDoc} */
  @Override
  public void onGeolocationPermissionsHidePrompt()
  {
    mWrappedClient.onGeolocationPermissionsHidePrompt();
  }

  /** {@inheritDoc} */
  @Override
  public boolean onJsTimeout()
  {
    return mWrappedClient.onJsTimeout();
  }

  /** {@inheritDoc} */
  @Override
  @Deprecated
  public void onConsoleMessage(String message, int lineNumber, String sourceID)
  {
    mWrappedClient.onConsoleMessage(message, lineNumber, sourceID);
  }

  /** {@inheritDoc} */
  @Override
  public boolean onConsoleMessage(ConsoleMessage consoleMessage)
  {
    return mWrappedClient.onConsoleMessage(consoleMessage);
  }

  /** {@inheritDoc} */
  @Override
  public Bitmap getDefaultVideoPoster()
  {
    return mWrappedClient.getDefaultVideoPoster();
  }

  /** {@inheritDoc} */
  @Override
  public View getVideoLoadingProgressView()
  {
    return mWrappedClient.getVideoLoadingProgressView();
  }

  /** {@inheritDoc} */
  @Override
  public void getVisitedHistory(ValueCallback<String[]> callback)
  {
    mWrappedClient.getVisitedHistory(callback);
  }

  /** {@inheritDoc} */

  public void openFileChooser(ValueCallback<Uri> uploadFile)
  {
    ((TestWebChromeClient) mWrappedClient).openFileChooser(uploadFile);
  }

  /** {@inheritDoc} */

  public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType)
  {
    ((TestWebChromeClient) mWrappedClient).openFileChooser(uploadFile, acceptType);
  }

  /** {@inheritDoc} */

  public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType,
      String capture)
  {
    ((TestWebChromeClient) mWrappedClient).openFileChooser(uploadFile, acceptType,
        capture);
  }
}

 一下是setWebChromeClient需要添加的方法。

public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType)
      {
        openFileChooser(uploadFile);
      }

      public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType,
          String capture)
      {
        openFileChooser(uploadFile);
      }

尽管前面很多部分都不难找到,但是后面这段3.0和4.0坑爹隐藏代码实在让人惨死。我当初都差点放弃了,国内论坛我还没有发现到关于这个描述,所以我就在这里分享一下,也当作是马克,省得以后忘记了。

这回终于不用再被骂娘了,感谢CCAV,感谢TVC,感谢老爸,感谢老妈,感谢老外。

    各位有什么不懂的欢迎交流,可以来关注我新浪微博    琴弦欲奏    ,欢迎共同探讨Android的应用开发的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值