android webView加载页面的交互

       作为一个从业多年的研发人员,居然犯了一个最最低级的错误:功能的实现,居然听了产品妹子的瞎咧咧,导致发布出去的产品出现了尴尬的一幕;

我惭愧,我忏悔啊!!!!!!!

      故事是这样的

      产品妹子:咱们的产品需要接入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 ,比安卓简单多了,


这些看是简单的问题,其实隐藏了不少知识点,小生就在此简单记录一下,希望可以给自己和遇到类似问题的同学有所帮助。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值