作为一个从业多年的研发人员,居然犯了一个最最低级的错误:功能的实现,居然听了产品妹子的瞎咧咧,导致发布出去的产品出现了尴尬的一幕;
我惭愧,我忏悔啊!!!!!!!
故事是这样的
产品妹子:咱们的产品需要接入XX客服,后台已经接入完成,非常简单只需要用浏览器加载一个url地址就好了
我:no problem,分分钟钟的事情
于是乎,哥把这事就很放心的交给了一个同事去做,心想这么简单,何须哥亲自出马
五分钟,十分钟过去了,
研发小妹:师傅,我修改完了
我:测试一下没问题就发测试了
研发小妹:测过了,没发现什么问题,那我就发测试了
测试的同学也努力的测试了android ,IOS 版本,最后发布上线,,,可谓是万事大吉了
大家都高高兴兴的过了个春节,
然而美梦终究不会长久。。。。
出问题了,app上客服没法发送图片,android点击后没响应,IOS会弹出来选择图片/拍照,但是选择后还是不会发送给客服;
这尼玛什么鬼场景哦,一样的浏览器加载,一样的方式咋就不一样的效果呢
看来这回是需要小生亲自来搞了,咋用着用着就出问题了呢,这群小学生真的是靠不住啊,也怪小生太大意了
先来说说android:
幸好哥之前搞过webkit内核的开发,一看代码怎么可能webview不做任何设置就可以从一个url地址中的按钮会自动调用android的代码呢?
反正这事,哥不信,你信不信就由你了。
那到底该怎么设置呢,设置哪些呢? 带着这些问题,又去拜访了一下度娘,
果不其然,
度娘支招:
要想响应url地址中的打开文件的事件,需要给webview 设置webChromeClient ,来实现openFileChooser回调
于是,按照度娘的指点,哥照做了,然而在3.0 ,4.4 , 7.1的设备上进行了测试,发现有些是可以交互,有些是不可以,难道这个方法还会针对不同的系统版本有所不同?
这回不用度娘了,研究一下webChromeClient和webView的源码吧,
TNND ,原来是这么一回事,
于是修改成如下代码:
WebSettings webSettings = myserviceWeb.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setBuiltInZoomControls(false);
myserviceWeb.loadUrl(GlobalSettingParameter.K_MYSERVICE_URL);
myserviceWeb.setWebChromeClient(new WebChromeClient() {
/**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
* onReceiveValue must be called to wake up the thread.a
* @param acceptType The value of the 'accept' attribute of the input tag
* associated with this file picker.
* @param capture The value of the 'capture' attribute of the input tag
* associated with this file picker.
* @hide
*/
// for android <3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "", "");
}
// for android >3.0 <4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType) {
openFileChooser(uploadMsg, acceptType, "");
}
// for android > 4.1
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType, String capture) {
mUploadMessage = uploadMsg;
//此处来实现弹出的选择文件的菜单,或者直接去选择文件也可以
}
});
这里我使用的是自己的弹出选择菜单的dialog: camera ,photo ,那么选择的图片又如何返回到webView中去呢?
先不管这些了,先把这些返回的数据在onActivityResult中得到
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
ContentResolver resolver = getContentResolver();
switch (requestCode) {
case PHOTO_COMPILE:// 照片的处理结果
{
if (data != null) {
String path = getAbsoluteImagePath(data.getData());
Bitmap bitmap = getimage(path);
// 转成url
Uri imageUri = Uri.parse(MediaStore.Images.Media.insertImage(
getContentResolver(), bitmap, null, null));
Uri result = data == null || resultCode != RESULT_OK ? null
: data.getData();
// 上传图片
mUploadMessage.onReceiveValue(result);
} else {
mUploadMessage.onReceiveValue(null);
mUploadMessage = null;
}
}
break;
case PHOTO_CAMERA:// 拍照
{
// 设置文件保存路径这里放在跟目录下
File picture = new File(photoPath);
// 进行图片的压缩
Bitmap bitmap1 = getimage(picture.getPath());
if (bitmap1 != null) {
// 转成url
Uri imageUri = Uri.parse(MediaStore.Images.Media.insertImage(
getContentResolver(), bitmap1, null, null));
// 上传图片
mUploadMessage.onReceiveValue(imageUri);
} else {
mUploadMessage.onReceiveValue(null);
mUploadMessage = null;
}
}
break;
default:
break;
}
}
这样一下就搞定了,
下面把对应用到的方法代码也贴出来:
private Bitmap getimage(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 800f;// 这里设置高度为800f
float ww = 480f;// 这里设置宽度为480f
// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;// be=1表示不缩放
if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;// 设置缩放比例
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
if (bitmap != null) {
return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩
} else {
return null;
}
}
private Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();// 重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
options -= 10;// 每次都减少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
return bitmap;
}
protected String getAbsoluteImagePath(Uri uri) {
// can post image
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, // Which columns to return
null, // WHERE clause; which rows to return (all rows)
null, // WHERE clause selection arguments (none)
null); // Order-by clause (ascending by name)
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
这回经过一番测试后,没问题了,那就打个测试包吧,
然而,显示是非常残酷的,正式包一下又回到解放前,
NMD,这个如何是好哦?
明明我测试的没问题,怎么打包了就不行了,难道是打包出了问题?
于是我把打包中新增的代码混淆注释掉
再次打包,对了
哦,原来是代码混淆在这里捣乱
哈哈哈,哥把这个activity取消混淆,
再打包,
啊,还不得行,
又去看了一下源码注释:
/**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
* onReceiveValue must be called to wake up the thread.a
* @param acceptType The value of the 'accept' attribute of the input tag
* associated with this file picker.
* @param capture The value of the 'capture' attribute of the input tag
* associated with this file picker.
* @hide
*/
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
uploadFile.onReceiveValue(null);
}
大家有没看到@hide ,这个方法不是对外开放的,代码混淆的时候会被混淆掉,这就好办了,只需要在混淆文件proguard.cfg 中添加如下代码:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
这回总可以了吧,打包自测试,提交测试都没得问题了。。。。
哎,android是搞定了,IOS还在等待中呢
接着去奋斗吧,骚年
不过有了android的思路,去解决IOS是不是so easy ?
奇怪的是,IOS并不会如愿,难道又有什么奇葩事情?
度娘给了一堆答案,其实说白了都是大家转发的,都比较雷同
那难道这个就成了一个宇宙之谜了?
通过用safri和腾讯的测试,发现别人都可以,为毛我的app不行了,
我就奇了怪了
于是撇开app,自己新建一个demo,里面只放了UIWebView,诶,这回又可以了
经过一番比对后,发现在初始化UIWebView放到了viewDidAppear中去了,修改到viewDidLoad中即可,
苹果果然NB ,比安卓简单多了,
这些看是简单的问题,其实隐藏了不少知识点,小生就在此简单记录一下,希望可以给自己和遇到类似问题的同学有所帮助。