安卓在手机上看电视直播的demo(二)——自动获取直播地址

上一个demo是手动添加直播地址到项目中,要经历抓包、复制URL到xml文件、复制图片到drawable文件夹下等过程,比较麻烦。这次我们在app里面写好代码,运行的时候自动获取直播链接。这么做虽然省去了人工添加的步骤,但是也有很多缺点,比如:当网页结构改变时要修改源代码,动态获取直播链接比较耗时,而且有可能会获取不到链接。

本次demo的开发有些牵强,效果是实现了,却有东拼西凑的感觉。算了,不管这么多了,先记录下来。

效果图:

查看网页结构

我这里以电视眼为例。抓包看了一下,没有返回json之类的数据,只能从HTML源码入手了。通过审查元素,发现网页结构比较有规律,电视的播放页面都是在class为tv的ul标签里,包括超链接和台标图片。

用jsoup对其解析,生成javabean对象,放到list集合当中。代码有点多,有点乱,我只放上关键代码。

        Connection connect = Jsoup.connect(mUrl);
		try {
			Document document = connect.get();
			Elements lis = document.getElementsByClass("tv").select("li");
			if (lis.size() == 0) {
				Log.e("没有li", "大小为0");
				return;
			}
			tvItems = new ArrayList<TvItem>();
			for (Element element : lis) {
				TvItem item = new TvItem();
				String ahref = element.select("a").attr("abs:href");
				String imgsrc = element.select("img").attr("abs:src");
				String imgalt = element.select("img").attr("alt");
				item.setImgUrl(imgsrc);
				item.setOriginalUrl(ahref);
				item.setTitle(imgalt);
				tvItems.add(item);
			}

		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();

		}

在MainActivity中放一个GridView,展示javabean中的内容。

设置GridView的item的点击事件,当点击item的时候,取出javabean里的播放链接,跳转到PlayActivity播放。

但是javabean里的播放链接是html网页的链接,不能直接扔到mediaplayer加载,因此要从originalURL嗅探到真实的m3u8地址。可以通过WebView模拟浏览器请求,截获请求的URL,如果URL包含.m3u8,就表明获取到了真实的地址。道理是这样,但是实际当中可能得到多条包含.m3u8的地址,而且有些并不是真正的视频地址,所以还要再处理一下。具体怎么处理,根据实际情况来定。

通过重写WebViewClient的onLoadResource方法截获URL,如果网址中包含了.m3u8则把它记录到成员变量当中。

	@Override
	public void onLoadResource(WebView view, String url) {
		// TODO 自动生成的方法存根
		if (url.contains(".m3u8")) {
			Log.e("发现了", url);
			mUrl = url;
		}
		if (mUrl.endsWith(".m3u8")) {
			Message msg = new Message();
			msg.what = MyWebViewClient.FIND_ONE;
			handler.sendMessage(msg);
		}
	}

当网页加载完毕的时候,通过intent发消息给MainActivity,把真实的m3u8地址传过去,让MainActivity去启动PlayActivity播放

如何在webview中判断网页是否真的加载完毕呢?

网上很多办法都是在onPageFinished方法里直接进行判断。但是经过我的测试,这种办法在有异步请求时根本行不通。可能会调用多次onPageFinished,第一次调用时让我们以为网页加载完了,实际上并没有。还有一种办法是在安卓代码中向webview注入JavaScript,重写window.onload()。这种方法也是有问题的,多次重写window.onload只会调用一次,无法确定是调用谁的。

我采取的办法是在网上偶然发现的,也是利用了JavaScript。

在onPageFinished中执行一段js代码,这段代码没有重写window.onload,就是一个普通的函数,因此肯定会执行到函数里面的代码。在函数里判断document.readyState这个标志,如果等于complete,说明页面已加载完毕,这样更保险一点。

	@Override
	public void onPageFinished(WebView view, String url) {
		view.evaluateJavascript(
				"function isOK(){if(document.readyState == 'complete'){alert('OK');return 'OK';}}isOK(); ",
				new ValueCallback<String>() {

					@Override
					public void onReceiveValue(String value) {
						// TODO 自动生成的方法存根
						if ("OK".equals(value)) {
							Log.e("完成的标志", value);
						}
						Log.e("接收到", value);
					}
				});
		super.onPageFinished(view, url);
	}

如果在JavaScript中return,直接在onReceiveValue回调函数中进行判断

如果在JavaScript中alert,需要进行下面的设置:

		webView.getSettings().setJavaScriptEnabled(true);
		webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

然后WebChromeClient中重写onJsAlert

	@Override
	public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
		// TODO 自动生成的方法存根
		if (message.equals("OK")) {
			Log.e("页面加载完成", "javascript");
			mHandler.sendEmptyMessage(MyWebViewClient.PAGE_FINISHED);
		}
		//不加这句的话,再次载入URL会直接提示页面加载完毕
		result.cancel();
		return true;
	}

到这里项目中需要注意的地方就介绍结束了,剩下的部分和之前的demo类似,不再赘述。

百度云下载:https://pan.baidu.com/s/1uhGS13sDCM7bSdqzzo-TGw

猜你喜欢

转载自blog.csdn.net/qq_40582463/article/details/81628979