展会信息港展会大全

Android开发心得——网页通过webview调用Android的图片或文件选择
来源:互联网   发布日期:2015-10-02 21:31:15   浏览:1808次  

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

前段时间因为客户需求,做一个客户端结合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的应用开发的问题。

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港