Android 实战 - 个人App乐逗项目(查看网页链接封装,播放视频封装)
来源:互联网 发布:unity3d 路径动画 编辑:程序博客网 时间:2024/05/20 16:10
1.查看网页链接封装
和 Android实战-个人App乐逗项目(第一阶段:微信精选文章完成与总结) 中的webview一样,采用腾讯x5浏览服务sdk调用的.
效果 预览 :
所需 工具 :
- 腾讯x5浏览服务sdk 或者点击下载 jar
可以到官方下载,或者点击下载 对应jar包即可.
- 封装 x5webview , 前提是导入上面的jar
//SecurityJsBridgeBundle.java
package labelnet.cn.ledou.ui;import android.content.Context;import java.util.Map;/** * X5WebView , 应用类 , 提供JSBridge */public abstract class SecurityJsBridgeBundle { /////////////////////////////////////////////////////////////////////////////// //add js private final static String DEFAULT_JS_BRIDGE ="JsBridge"; public static final String METHOD = "method"; public static final String BLOCK = "block"; public static final String CALLBACK = "callback"; public static final String PROMPT_START_OFFSET = "local_js_bridge::"; private Context mContext; private String mJsBlockName ; private String mMethodName; public abstract void onCallMethod(); public SecurityJsBridgeBundle(String JsBlockName, String methodName) throws Exception{ if(methodName == null){ throw new Exception("methodName can not be null!"); } if(JsBlockName!=null){ this.mJsBlockName=JsBlockName; }else{ this.mJsBlockName = DEFAULT_JS_BRIDGE; } } public String getMethodName(){ return this.mMethodName; } public String getJsBlockName(){ return this.mJsBlockName; } private void injectJsMsgPipecode(Map<String,Object> data){ if(data==null){ return ; } String injectCode = "javascript:(function JsAddJavascriptInterface_(){ "+ "if (typeof(window.jsInterface)!='undefined') {"+ "console.log('window.jsInterface_js_interface_name is exist!!');} "+ "else {"+ data.get(BLOCK)+data.get(METHOD)+ "window.jsBridge = {"+ "onButtonClick:function(arg0) {"+ "return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));"+ "},"+ "onImageClick:function(arg0,arg1,arg2) {"+ "prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));"+ "},"+ "};"+ "}"+ "}"+ ")()"; } private static String getStandardMethodSignature(){ return null; }}
//x5webview.java
package labelnet.cn.ledou.ui;import android.annotation.SuppressLint;import android.app.Activity;import android.app.AlertDialog;import android.app.AlertDialog.Builder;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.net.Uri;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient.CustomViewCallback;import com.tencent.smtt.export.external.interfaces.JsPromptResult;import com.tencent.smtt.export.external.interfaces.JsResult;import com.tencent.smtt.export.external.interfaces.WebResourceResponse;import com.tencent.smtt.sdk.ValueCallback;import com.tencent.smtt.sdk.WebChromeClient;import com.tencent.smtt.sdk.WebSettings;import com.tencent.smtt.sdk.WebSettings.LayoutAlgorithm;import com.tencent.smtt.sdk.WebStorage;import com.tencent.smtt.sdk.WebView;import com.tencent.smtt.sdk.WebViewClient;import java.util.HashMap;import java.util.Map;import labelnet.cn.ledou.R;public class X5WebView extends WebView { /////////////////////////////////////////////////// //add private object ////////////////////////////////////////////////// //file chooser result code public static final int FILE_CHOOSER = 0; private String resourceUrl = ""; private WebView smallWebView; private static boolean isSmallWebViewDisplayed = false; private Map<String, Object> mJsBridges; @SuppressLint("SetJavaScriptEnabled") public X5WebView(Context arg0, AttributeSet arg1) { super(arg0, arg1); WebStorage webStorage = WebStorage.getInstance(); // TODO Auto-generated constructor stub WebSettings webSetting = this.getSettings(); webSetting.setJavaScriptEnabled(true); webSetting.setJavaScriptCanOpenWindowsAutomatically(true); webSetting.setAllowFileAccess(true); webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); webSetting.setSupportZoom(true); webSetting.setBuiltInZoomControls(true); webSetting.setUseWideViewPort(true); webSetting.setSupportMultipleWindows(true); webSetting.setLoadWithOverviewMode(true); webSetting.setAppCacheEnabled(true); webSetting.setDatabaseEnabled(true); webSetting.setDomStorageEnabled(true); webSetting.setGeolocationEnabled(true); webSetting.setAppCacheMaxSize(Long.MAX_VALUE); // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY); webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND); webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH); webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE); this.getView().setClickable(true); this.getView().setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return false; } }); //WebClient settings this.setWebViewClient(new WebViewClient() { /** * 防止加载网页时调起系统浏览器 */ public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true;// return false; } public void onReceivedHttpAuthRequest(WebView webview, com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, String host, String realm) { boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword(); Log.i("yuanhaizhou", "useHttpAuthUsernamePassword is" + flag); Log.i("yuanhaizhou", "HttpAuth host is" + host); Log.i("yuanhaizhou", "HttpAuth realm is" + realm); } @Override public void onDetectedBlankScreen(String arg0, int arg1) { // TODO Auto-generated method stub super.onDetectedBlankScreen(arg0, arg1); } @Override public WebResourceResponse shouldInterceptRequest(WebView arg0, String arg1) { // TODO Auto-generated method stub return super.shouldInterceptRequest(arg0, arg1); } }); //webchromeclient settings this.setWebChromeClient(new WebChromeClient() { View myVideoView; View myNormalView; CustomViewCallback callback; /////////////////////////////////////////////////////////// // /** * 全屏播放配置 */ @Override public void onShowCustomView(View view, CustomViewCallback customViewCallback) { // TODO Auto-generated method stub FrameLayout normalView = (FrameLayout) ((Activity) getContext()).findViewById(R.id.web_filechooser); ViewGroup viewGroup = (ViewGroup) normalView.getParent(); viewGroup.removeView(normalView); viewGroup.addView(view); myVideoView = view; myNormalView = normalView; callback = customViewCallback; } @Override public void onHideCustomView() { // TODO Auto-generated method stub if (callback != null) { callback.onCustomViewHidden(); callback = null; } if (myVideoView != null) { ViewGroup viewGroup = (ViewGroup) myVideoView.getParent(); viewGroup.removeView(myVideoView); viewGroup.addView(myNormalView); } } @Override public void onProgressChanged(WebView arg0, int arg1) { // TODO Auto-generated method stub super.onProgressChanged(arg0, arg1); } @Override public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String captureType) { Log.i("ChromeClient", "openFileChooser enter"); Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); ((Activity) (X5WebView.this.getContext())).startActivityForResult( Intent.createChooser( i, "choose files"), X5WebView.FILE_CHOOSER); super.openFileChooser(uploadFile, acceptType, captureType); } @Override public void onShowCustomView(View arg0, int arg1, CustomViewCallback arg2) { // TODO Auto-generated method stub CustomViewCallback callback = new CustomViewCallback() { @Override public void onCustomViewHidden() { // TODO Auto-generated method stub Log.i("yuanhaizhou", "video view hidden"); } }; super.onShowCustomView(arg0, arg1, arg2); } /** * webview 的窗口转移 */ @Override public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, Message msg) { // TODO Auto-generated method stub Log.i("yuanhaihzou", "onCreateWindow happend!!"); if (X5WebView.isSmallWebViewDisplayed == true) { WebView.WebViewTransport webViewTransport = (WebView.WebViewTransport) msg.obj; WebView webView = new WebView(X5WebView.this.getContext()) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setTextSize(15); canvas.drawText("新建窗口", 10, 10, paint); } ; }; webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView arg0, String arg1) { arg0.loadUrl(arg1); return true; } ; }); FrameLayout.LayoutParams lp = new LayoutParams(400, 600); lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL; X5WebView.this.addView(webView, lp); webViewTransport.setWebView(webView); msg.sendToTarget(); } return true; } @Override public boolean onJsAlert(WebView arg0, String arg1, String arg2, JsResult arg3) { // TODO Auto-generated method stub AlertDialog.Builder builder = new Builder(getContext()); builder.setTitle("X5内核"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub dialog.dismiss(); } }); builder.show(); arg3.confirm(); return true; } /** *对应js 的通知弹框 ,可以用来实现js 和 android之间的通信 */ @Override public boolean onJsPrompt(WebView arg0, String arg1, String arg2, String arg3, JsPromptResult arg4) { // TODO Auto-generated method stub //在这里可以判定js传过来的数据,用于调起android native 方法 if (X5WebView.this.isMsgPrompt(arg1)) { if (X5WebView.this.onJsPrompt(arg2, arg3)) { return true; } else { return false; } } return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4); } @Override public void onReceivedTitle(WebView arg0, final String arg1) { // TODO Auto-generated method stub super.onReceivedTitle(arg0, arg1); Log.i("yuanhaizhou", "webpage title is " + arg1); } }); } ///////////////////////////////////////////////////////////////////// //绘制webview的标记 @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean ret = super.drawChild(canvas, child, drawingTime); canvas.save(); Paint paint = new Paint(); paint.setColor(0x7fff0000); paint.setTextSize(24.f); paint.setAntiAlias(true); /** * 取消绘制的标识 * 包括内核 * 手机信息 * 手机名称 */// if (getX5WebViewExtension() != null) {// //Log.d(TAG, "drawChild--X5 Core");// canvas.drawText(this.getContext().getPackageName() + "-pid:" + android.os.Process.myPid(), 10, 50, paint);// canvas.drawText("X5 Core:" + QbSdk.getTbsVersion(this.getContext()), 10, 100, paint);// } else {// //Log.d(TAG, "drawChild--Sys Core");// canvas.drawText(this.getContext().getPackageName() + "-pid:" + android.os.Process.myPid(), 10, 50, paint);// canvas.drawText("Sys Core", 10, 100, paint);// }// canvas.drawText(Build.MANUFACTURER, 10, 150, paint);// canvas.drawText(Build.MODEL, 10, 200, paint); canvas.restore(); return ret; } public X5WebView(Context arg0) { super(arg0); setBackgroundColor(85621); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub return super.onInterceptTouchEvent(ev); } public static void setSmallWebViewEnabled(boolean enabled) { isSmallWebViewDisplayed = enabled; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { // TODO Auto-generated method stub// Log.i("yuanhaizhou","webview scroll y is" +this.getView().getScrollY());// Log.i("yuanhaizhou","real webview scroll y is" + this.getScrollY());// Log.i("yuanhaizhou","webview webscroll y is" + this.getWebScrollY()); Log.i("yuanhaizhou", "webview webscroll y is" + this.getWebScrollY()); super.onScrollChanged(l, t, oldl, oldt); } public void addJavascriptBridge(SecurityJsBridgeBundle jsBridgeBundle) { if (this.mJsBridges == null) { this.mJsBridges = new HashMap<String, Object>(5); } if (jsBridgeBundle != null) { String tag = SecurityJsBridgeBundle.BLOCK + jsBridgeBundle.getJsBlockName() + "-" + SecurityJsBridgeBundle.METHOD + jsBridgeBundle.getMethodName(); this.mJsBridges.put(tag, jsBridgeBundle); } } /** * 当webchromeClient收到 web的prompt请求后进行拦截判断,用于调起本地android方法 * * @param methodName 方法名称 * @param blockName 区块名称 * @return true :调用成功 ; false :调用失败 */ private boolean onJsPrompt(String methodName, String blockName) { String tag = SecurityJsBridgeBundle.BLOCK + blockName + "-" + SecurityJsBridgeBundle.METHOD + methodName; if (this.mJsBridges != null && this.mJsBridges.containsKey(tag)) { ((SecurityJsBridgeBundle) this.mJsBridges.get(tag)).onCallMethod(); return true; } else { return false; } } /** * 判定当前的prompt消息是否为用于调用native方法的消息 * * @param msg 消息名称 * @return true 属于prompt消息方法的调用 */ private boolean isMsgPrompt(String msg) { if (msg != null && msg.startsWith(SecurityJsBridgeBundle.PROMPT_START_OFFSET)) { return true; } else { return false; } }}
布局 实现 :
引入刚才的自定义x5Webview
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/zhushen_color"> <labelnet.cn.ledou.ui.X5WebView android:id="@+id/web_tb_filechooser" android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_marginTop="20dp" /></RelativeLayout>
业务 实现 :
package labelnet.cn.ledou;import android.app.ProgressDialog;import android.graphics.Bitmap;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Toast;import com.tencent.smtt.sdk.WebView;import com.tencent.smtt.sdk.WebViewClient;import labelnet.cn.ledou.net.NetManager;import labelnet.cn.ledou.net.NetManagerImp;import labelnet.cn.ledou.ui.X5WebView;/** * Created by yuan on 15-11-9. * <p/> * 公共的 Webview ,用来打开网页使用 */public class TbOtherHtmlActivity extends AppCompatActivity { private NetManager netManager; private ProgressDialog progressDialog; private String copy_url = "www.labelnet.cn"; private Bitmap bitmap; private X5WebView x5WebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tbotherhtml); x5WebView = (X5WebView) findViewById(R.id.web_tb_filechooser); //一些初始化 initProgressBar(); netManager = new NetManagerImp(); x5WebView.setSmallWebViewEnabled(true); x5WebView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView webView, String s, Bitmap bitmap) { progressDialog.show(); } @Override public void onPageFinished(WebView webView, String s) { progressDialog.dismiss(); } }); initData(); } private void initData() { String url = getIntent().getStringExtra("url"); this.copy_url = url; if (url == null) { progressDialog.dismiss(); showToast("网络链接失败,请重试!"); } else { x5WebView.loadUrl(url); } } /** * 初始化 Progressdialog */ private void initProgressBar() { progressDialog = new ProgressDialog(this); progressDialog.setMessage("小鱼说: 请稍后"); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); } /** * toast * * @param msg */ private void showToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } /** * 退出按钮 */ @Override public void onBackPressed() { progressDialog.dismiss(); finish(); }}
调用 实现 :
这里仅仅是传入了地址链接和title , 其他的可以自定义.
Intent intent = new Intent(MainLeActivity.this, TbMusicActivity.class); intent.putExtra("url", url); intent.putExtra("title",title ); startActivity(intent);
2.播放视频封装
说明: 点击播放 - > 全屏加载播放 -> 可以暂停播放控制
这个还没有进行优化,仅仅是可以播放视频,没有自己的,可控制的内容.
效果 预览 :
在模拟器上播放不了,这里就在真机上截屏了
所需 工具 :
采用VideoView实现 , 不需要工具类
VideoView 的一些参数 :
方法说明:
getBufferPercentage:得到缓冲的百分比
getCurrentPosition:得到当前播放位置
getDuration:得到视频文件的时间
resolveAdjustedSize:调整视频显示大小
setMediaController:设置播放控制器模式(播放进度条)
setOnCompletionListener:当视频文件播放完时触发事件
setVideoPath:设置视频源路径
setVideoURI:设置视频源地址
布局 实现 :
采用VideoView实现
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <VideoView android:id="@+id/tb_videoview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tb_video_progress" android:layout_gravity="center" /></FrameLayout>
业务 实现 :
package labelnet.cn.ledou;import android.app.Activity;import android.content.pm.ActivityInfo;import android.media.MediaPlayer;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.MediaController;import android.widget.ProgressBar;import android.widget.Toast;import com.gitonway.lee.niftymodaldialogeffects.lib.Effectstype;import com.gitonway.lee.niftymodaldialogeffects.lib.NiftyDialogBuilder;import labelnet.cn.ledou.ui.TbVideoView;/** * Created by yuan on 15-11-6. * 播放视频的Activity */public class TbVideoActivity extends Activity implements View.OnClickListener { private TbVideoView tb_videoview; private String url, title; private ProgressBar tb_video_progress; private NiftyDialogBuilder dialogBuilder; @Override protected void onResume() { super.onResume(); //设置初始的时候,就横屏和全屏 if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //隐藏标题 requestWindowFeature(Window.FEATURE_NO_TITLE); //设置全屏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_tbvideo); initView(); initData(); } /** * 准备数据 */ private void initData() { url = getIntent().getStringExtra("url"); title = getIntent().getStringExtra("title"); videoPlay(); } /** * 播放视频 */ private void videoPlay() { tb_videoview.setVideoURI(Uri.parse(url)); tb_videoview.setMediaController(new MediaController(this)); tb_videoview.requestFocus(); //自动播放 tb_videoview.start(); } /** * 初始化 */ private void initView() { tb_videoview = (TbVideoView) findViewById(R.id.tb_videoview); tb_videoview.setOnClickListener(this); tb_video_progress = (ProgressBar) findViewById(R.id.tb_video_progress); tb_videoview.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //onPrepared 加载好,后进度条消失 tb_video_progress.setVisibility(View.GONE); } }); /** * 加载出错的情况下 */ tb_videoview.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { showToast("咦,网络打小报告了?"); tb_video_progress.setVisibility(View.GONE); return false; } }); /** * 播放完毕的监听 */ tb_videoview.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { showToast("播放完了"); getDialogShow("嘿嘿,播放完了"); } }); } private void showToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); } protected void getDialogShow(String msg) { dialogBuilder .withTitle("温馨提示") .withDividerColor("#808080") .withMessage(msg) .withDialogColor("#808080") .withDuration(700) .withEffect(Effectstype.Fadein) .withButton1Text("返回") .setButton1Click(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }) .show(); } /** * 最大化视频 */ @Override public void onBackPressed() { super.onBackPressed(); if (tb_videoview.isPlaying()) { tb_videoview.clearFocus(); } finish(); } @Override public void onClick(View v) { //showToast("我是title"); }}
调用 实现 :
Intent intent = new Intent(MainLeActivity.this, TbMusicActivity.class); intent.putExtra("url", url); intent.putExtra("title",title ); startActivity(intent);
3.总结
这几个都是些简单的实现,后续功能 还需要添加和完善.
下篇实现音乐播放器.
- Android 实战 - 个人App乐逗项目(查看网页链接封装,播放视频封装)
- Android 实战 - 个人App乐逗项目 之 查看图片,查看GIF封装
- Android 实战 - 个人APP乐逗项目(内部音乐播放器实现,开源MaskProgressView使用)
- Android实战 - 个人App 乐逗项目 开启篇
- android利用videoView播放视频(已封装)
- Android视频播放框架——封装FFMPEG的Vitamio
- Android实战 - 个人App 乐逗项目 (实现初始化页面,引导页)
- Android AIDL技术实战项目-音乐播放器(二)-使用retrofit完成音乐API的封装
- 个人封装的一个播放模块
- iOS 基于AVPLayer封装视频播放器
- MediaPlayer封装原生视频播放器
- 个人封装!
- APP开发实战138-代码封装
- Android实战-个人App乐逗项目(第一阶段:微信精选文章完成与总结)
- IJKPlayer的封装视频播放器封装,Swift编写。仿今日头条视频播放器。
- android 简单的实现视频的播放 基于 ijkplayer的封装更加简单 方便快捷
- android 简单的实现视频的播放 基于 ijkplayer的封装更加简单 方便快捷
- RN实战项目网络请求封装(二)
- List<String>Sort
- iOS开发之GCD使用总结
- 希尔排序:Java(最小增量排序)
- Spark学习体会
- java快速排序实现
- Android 实战 - 个人App乐逗项目(查看网页链接封装,播放视频封装)
- Binary Tree Upside Down
- LeetCode Regular Expression Matching
- 常用排序算法稳定性、时间复杂度分析
- 乐视推相亲节目,“十周嫁出去”为何深得网友支持?
- 显示Intent和隐式Intent的区别
- 欢迎使用CSDN-markdown编辑器
- c++头文件
- Java学习笔记(八)异常及图形界面