任何人都可以帮助使用此代码来播放嵌入网站的YouTube视频吗? 我已经尝试过各种各样的东西,包括在manifest中的hardwareAccelerated = true。
webview显示youtube页面和缩略图,但点击它们时没有任何反应。
在某些具有hardwareAccelerated的设备上,它播放声音但没有视频。 谢谢大家!
package com.inglesupdated;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Picture;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebView.PictureListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class BT_screen_customURL extends BT_activity_base{
private boolean didCreate = false;
private WebView webView = null;
private String dataURL = "";
private String currentURL = "";
private String originalURL = "";
private AlertDialog confirmLaunchInNativeAppDialogue = null;
private AlertDialog confirmEmailDocumentDialogue = null;
private String showBrowserBarBack = "";
private String showBrowserBarLaunchInNativeApp = "";
private String showBrowserBarEmailDocument = "";
private String showBrowserBarRefresh = "";
//////////////////////////////////////////////////////////////////////////
//activity life-cycle events.
//onCreate
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.activityName = "BT_screen_customURL";
BT_debugger.showIt(activityName + ":onCreate");
//reference to base layout..
LinearLayout baseView = (LinearLayout)findViewById(R.id.baseView);
//setup background colors...
BT_viewUtilities.updateBackgroundColorsForScreen(this, this.screenData);
//setup background images..
if(backgroundImageWorkerThread == null){
backgroundImageWorkerThread = new BackgroundImageWorkerThread();
backgroundImageWorkerThread.start();
}
//setup navigation bar...
LinearLayout navBar = BT_viewUtilities.getNavBarForScreen(this, this.screenData);
if(navBar != null){
baseView.addView(navBar);
}
//inflate this screens layout file...
LayoutInflater vi = (LayoutInflater)thisActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View thisScreensView = vi.inflate(R.layout.screen_customurl, null);
//add the view to the base view...
baseView.addView(thisScreensView);
//reference to the webview in the layout file.
webView = (WebView) thisScreensView.findViewById(R.id.webView);
webView.setBackgroundColor(0);
webView.setInitialScale(0);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setPluginsEnabled(true);
webView.setPictureListener(new MyPictureListener());
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url){
//remember the URL...
currentURL = url;
//load the URL in the app's built-in browser if it's in our list of types to load...
if(BT_act_controller.canLoadDocumentInWebView(url)){
//load url in built-in browser...
// showProgress(null, null);
return false;
}else{
//ask user what app to open this in if the method returned NO...
try{
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(Intent.createChooser(i, getString(R.string.openWithWhatApp)));
}catch(Exception e){
BT_debugger.showIt(activityName + ": Error launching native app for url: " + url);
showAlert(getString(R.string.noNativeAppTitle), getString(R.string.noNativeAppDescription));
}
//do not try to load the URL..
return true;
}
}
@Override
public void onPageFinished(WebView view, String url){
hideProgress();
BT_debugger.showIt(activityName + ":onPageFinished finished Loading: " + url);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
hideProgress();
showAlert(getString(R.string.errorTitle), getString(R.string.errorLoadingScreen));
BT_debugger.showIt(activityName = ":onReceivedError ERROR loading url: " + failingUrl + " Description: " + description);
}
});
//fill JSON properties...
dataURL = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "dataURL", "");
currentURL = dataURL;
originalURL = dataURL;
//button options for hardware menu key...
showBrowserBarBack = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "showBrowserBarBack", "0");
showBrowserBarLaunchInNativeApp = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "showBrowserBarLaunchInNativeApp", "0");
showBrowserBarEmailDocument = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "showBrowserBarEmailDocument", "0");
showBrowserBarRefresh = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "showBrowserBarRefresh", "0");
//prevent user interaction?
String preventUserInteraction = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "preventUserInteraction", "0");
if(preventUserInteraction.equalsIgnoreCase("1")){
//can't seem to get Android to "prevent user interaction"...???
}
//hide scroll bars..
String hideVerticalScrollBar = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "hideVerticalScrollBar", "0");
if(hideVerticalScrollBar.equalsIgnoreCase("1")){
webView.setVerticalScrollBarEnabled(false);
}
String hideHorizontalScrollBar = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "hideHorizontalScrollBar", "0");
if(hideHorizontalScrollBar.equalsIgnoreCase("1")){
webView.setHorizontalScrollBarEnabled(false);
}
String preventAllScrolling = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "preventAllScrolling", "0");
if(preventAllScrolling.equalsIgnoreCase("1")){
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
}
//figure out what to load...
if(dataURL.length() > 1){
String useUrl = BT_strings.mergeBTVariablesInString(dataURL);
BT_debugger.showIt(activityName + ": loading URL from: " + useUrl);
this.loadUrl(useUrl);
}else{
BT_debugger.showIt(activityName + ": No URL found? Not loading web-view!");
showAlert(getString(R.string.errorTitle), getString(R.string.errorLoadingScreen));
}
//flag as created..
didCreate = true;
/*
* *******************************************************************
Notes: This screen has fully loaded it's layout file at this point.
BT_activity_base loaded act_base.xml
--THEN--
this screen loaded it's own layout file.
JSON properties for this screen from the app's configuration data are
available for use. You can read these properties easily using the BT_strings class.
Example:
String thisScreensNavBarTitleText = BT_strings.getJsonPropertyValue(this.screenData.getJsonObject(), "thisScreensNavBarTitleText", "default value here");
The screens background and title bar were setup using the BT_viewUtilities class:
BT_viewUtilities.updateBackgroundColorsForScreen()
You are free to modify the layout file and extend this screen however you want.
********************************************************************
*/
}//onCreate
//onStart
@Override
protected void onStart() {
//BT_debugger.showIt(activityName + ":onStart");
super.onStart();
}
//onResume
@Override
public void onResume() {
super.onResume();
//BT_debugger.showIt(activityName + ":onResume");
//verify onCreate already ran...
if(didCreate){
}
}
//onPause
@Override
public void onPause() {
super.onPause();
//BT_debugger.showIt(activityName + ":onPause");
}
//onStop
@Override
protected void onStop(){
super.onStop();
//BT_debugger.showIt(activityName + ":onStop");
}
//onDestroy
@Override
public void onDestroy() {
super.onDestroy();
//BT_debugger.showIt(activityName + ":onDestroy");
}
//end activity life-cycle events
//////////////////////////////////////////////////////////////////////////
//load URL in webView
public void loadUrl(String theUrl){
BT_debugger.showIt(activityName + ": loadUrl");
try{
webView.loadUrl(theUrl);
}catch(Exception e){
BT_debugger.showIt(activityName + ":loadUrl Exception: " + e.toString());
}
}
/* Hardware Back-Key, uncomment as needed.
Uncomment this to make the hardware back-key act like a browser back button
Warning: If you do this the user will need to go "back" the number of times they
when "forward" to return to the previous screen.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()){
webView.goBack();
return true;
}
//not the back-key..
return super.onKeyDown(keyCode, event);
}
*/
//back button...
public void handleBackButton(){
BT_debugger.showIt(activityName + ":handleBackButton");
if(webView.canGoBack()){
webView.goBack();
}else{
BT_debugger.showIt(activityName + ":handleBackButton cannot go back?");
}
}
//refresh button...
public void handleRefreshButton(){
BT_debugger.showIt(activityName + ":handleRefreshButton");
if(currentURL.length() > 1){
showProgress(null, null);
webView.loadUrl(currentURL);
}else{
BT_debugger.showIt(activityName + ":handleRefreshButton cannot refresh?");
}
}
//launch in native app button...
public void handleLaunchInNativeAppButton(){
BT_debugger.showIt(activityName + ":handleLaunchInNativeAppButton");
if(currentURL.length() > 1 && originalURL.length() > 1){
confirmLaunchInNativeApp();
}else{
showAlert(getString(R.string.errorTitle), getString(R.string.cannotOpenDocumentInNativeApp));
BT_debugger.showIt(activityName + ":handleLaunchInNativeAppButton NO url?");
}
}
//handle email button
public void handleEmailDocumentButton(){
BT_debugger.showIt(activityName + ":handleLaunchInNativeAppButton");
showAlert(getString(R.string.errorTitle), getString(R.string.cannotEmailDocument));
BT_debugger.showIt(activityName + ":handleEmailDocumentButton NO document to email on URL screens");
}
//confirm launch in native app
public void confirmLaunchInNativeApp(){
confirmLaunchInNativeAppDialogue = new AlertDialog.Builder(this).create();
confirmLaunchInNativeAppDialogue.setTitle(getString(R.string.confirm));
confirmLaunchInNativeAppDialogue.setMessage(getString(R.string.confirmLaunchInNativeBrowser));
confirmLaunchInNativeAppDialogue.setIcon(R.drawable.icon);
//YES
confirmLaunchInNativeAppDialogue.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.yes), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
confirmLaunchInNativeAppDialogue.dismiss();
//tell Android to load the URL in the best available Native App...
try{
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(currentURL));
startActivity(i);
}catch(Exception e){
BT_debugger.showIt(activityName + ": Error launching native app for url: " + currentURL);
showAlert(getString(R.string.noNativeAppTitle), getString(R.string.noNativeAppDescription));
}
} });
//NO
confirmLaunchInNativeAppDialogue.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.no), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
confirmLaunchInNativeAppDialogue.dismiss();
} });
//show the confirmation box...
confirmLaunchInNativeAppDialogue.show();
}
//confirm email document
public void confirmEmailDocumentDialogue(){
confirmEmailDocumentDialogue = new AlertDialog.Builder(this).create();
confirmEmailDocumentDialogue.setTitle(getString(R.string.confirm));
confirmEmailDocumentDialogue.setMessage(getString(R.string.confirmEmailDocument));
confirmEmailDocumentDialogue.setIcon(R.drawable.icon);
//YES
confirmEmailDocumentDialogue.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.yes), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
confirmEmailDocumentDialogue.dismiss();
//tell Android launch the native email application...
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("plain/text");
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.sharingWithYou));
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, currentURL);
//chooser will propmpt user if they have more than one email client..
startActivity(Intent.createChooser(emailIntent, getString(R.string.openWithWhatApp)));
} });
//NO
confirmEmailDocumentDialogue.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.no), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
confirmEmailDocumentDialogue.dismiss();
} });
//show the confirmation box...
confirmEmailDocumentDialogue.show();
}
//see webView (above) where onPageFinished is loading too soon...
class MyPictureListener implements PictureListener {
public void onNewPicture(WebView view, Picture arg1) {
//BT_debugger.showIt("here" + ":onNewPicture done");
hideProgress();
}
}
/////////////////////////////////////////////////////
//options menu (hardware menu-button)
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
//set up dialog
final Dialog dialog = new Dialog(this);
//linear layout holds all the options...
LinearLayout optionsView = new LinearLayout(this);
optionsView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
optionsView.setOrientation(LinearLayout.VERTICAL);
optionsView.setGravity(Gravity.CENTER_VERTICAL);
optionsView.setPadding(0, 0, 0, 20);
//options have individual layout params
LinearLayout.LayoutParams btnLayoutParams = new LinearLayout.LayoutParams(400, LayoutParams.WRAP_CONTENT);
btnLayoutParams.setMargins(10, 10, 10, 10);
btnLayoutParams.leftMargin = 10;
btnLayoutParams.rightMargin = 10;
btnLayoutParams.topMargin = 0;
btnLayoutParams.bottomMargin = 10;
//holds all the options
ArrayList<Button> options = new ArrayList<Button>();
//cancel...
final Button btnCancel = new Button(this);
btnCancel.setText(getString(R.string.okClose));
btnCancel.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
}
});
options.add(btnCancel);
//back...
if(showBrowserBarBack.equalsIgnoreCase("1")){
final Button btn = new Button(this);
btn.setText(getString(R.string.browserBack));
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
handleBackButton();
}
});
options.add(btn);
}
//launch in native app...
if(showBrowserBarLaunchInNativeApp.equalsIgnoreCase("1")){
final Button btn = new Button(this);
btn.setText(getString(R.string.browserOpenInNativeApp));
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
handleLaunchInNativeAppButton();
}
});
options.add(btn);
}
//email document...
if(showBrowserBarEmailDocument.equalsIgnoreCase("1")){
final Button btn = new Button(this);
btn.setText(getString(R.string.browserEmailDocument));
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
handleEmailDocumentButton();
}
});
options.add(btn);
}
//refresh page...
if(showBrowserBarRefresh.equalsIgnoreCase("1")){
final Button btn = new Button(this);
btn.setText(getString(R.string.browserRefresh));
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
handleRefreshButton();
}
});
options.add(btn);
}
//refreshAppData (if we are on home screen)
if(this.screenData.isHomeScreen() && inglesupdated_appDelegate.rootApp.getDataURL().length() > 1){
final Button btnRefreshAppData = new Button(this);
btnRefreshAppData.setText(getString(R.string.refreshAppData));
btnRefreshAppData.setOnClickListener(new OnClickListener(){
public void onClick(View v){
dialog.cancel();
refreshAppData();
}
});
options.add(btnRefreshAppData);
}
//add each option to layout, set layoutParams as we go...
for(int x = 0; x < options.size(); x++){
options.get(x).setLayoutParams(btnLayoutParams);
options.get(x).setPadding(5, 5, 5, 5);
optionsView.addView(options.get(x));
}
//set content view..
dialog.setContentView(optionsView);
if(options.size() > 1){
dialog.setTitle(getString(R.string.menuOptions));
}else{
dialog.setTitle(getString(R.string.menuNoOptions));
}
//show
dialog.show();
return true;
}
//end options menu
/////////////////////////////////////////////////////
}
答案 0 :(得分:15)
尝试使用10个Google搜索页面中的不同解决方案在WebView中播放Youtube视频3天后,某些解决方案可以正常工作,但不是在每个设备或操作系统版本上,我决定以自己的方式思考。
对我来说,直接在WebView上播放视频的解决方案即使在最新的Android设备上也会生成许多工件:Nexus 4 因此,我必须找到一种方法来捕捉Youtube iframe上的点击,以便像iOS一样直接启动Youtube应用程序,而无需任何开发人员的努力。
public class MyWebViewClient extends WebViewClient {
public Activity mActivity;
public MyWebViewClient(Activity activity) {
super();
mActivity = activity;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = Uri.parse(url);
if (uri.getHost().contains("youtube.com")) {
IntentUtils.viewYoutube(mActivity, url);
return true;
}
return false;
}
public static void viewYoutube(Context context, String url) {
IntentUtils.viewWithPackageName(context, url, "com.google.android.youtube");
}
public static void viewWithPackageName(Context context, String url, String packageName) {
try {
Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (isAppInstalled(context, packageName)) {
viewIntent.setPackage(packageName);
}
context.startActivity(viewIntent);
} catch (Exception e) {
Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(viewIntent);
}
}
public static boolean isAppInstalled(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
try {
packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
return true;
} catch (NameNotFoundException e) {
}
return false;
}
@Override
public void onPageFinished(final WebView view, String url) {
String javascript = "javascript:" +
"var iframes = document.getElementsByTagName('iframe');" +
"for (var i = 0, l = iframes.length; i < l; i++) {" +
" var iframe = iframes[i]," +
" a = document.createElement('a');" +
" a.setAttribute('href', iframe.src);" +
" d = document.createElement('div');" +
" d.style.width = iframe.offsetWidth + 'px';" +
" d.style.height = iframe.offsetHeight + 'px';" +
" d.style.top = iframe.offsetTop + 'px';" +
" d.style.left = iframe.offsetLeft + 'px';" +
" d.style.position = 'absolute';" +
" d.style.opacity = '0';" +
" d.style.filter = 'alpha(opacity=0)';" +
" d.style.background = 'black';" +
" a.appendChild(d);" +
" iframe.offsetParent.appendChild(a);" +
"}";
view.loadUrl(javascript);
super.onPageFinished(view, url);
}
}
顺便说一句,我不得不说我为开发人员提供可接受的WebView所做的一些努力有点不高兴。
即使我理解仅基于HTML避免Android应用程序的愿望,它始终是在详细信息页面上显示丰富内容的最佳/最快方式。 例如,就我而言,我管理一个基于RSS的应用程序,允许我的客户自己更改内容。
此外,与Windows Phone开发相比,我们必须花费时间将UI与网络数据和保存的数据相关联,其中每个数据都直接链接到UI组件。
答案 1 :(得分:1)
Thomas G.的解决方案对我有用,但是我必须修改javascript。
String javascript = "javascript:" +
"setTimeout(function() {" +
" var iframes = document.getElementsByTagName('iframe');" +
" for (var i = 0, l = iframes.length; i < l; i++) {" +
" var iframe = iframes[i]," +
" a = document.createElement('a');" +
" a.setAttribute('href', iframe.src);" +
" d = document.createElement('div');" +
" d.style.width = iframe.offsetWidth + 'px';" +
" d.style.height = iframe.offsetHeight + 'px';" +
" d.style.top = iframe.offsetTop + 'px';" +
" d.style.left = iframe.offsetLeft + 'px';" +
" d.style.position = 'absolute';" +
" d.style.opacity = '0';" +
" d.style.filter = 'alpha(opacity=0)';" +
" d.style.zIndex='" + Integer.MAX_VALUE + "';" +
" d.style.background = 'black';" +
" a.appendChild(d);" +
" iframe.offsetParent.appendChild(a);" +
" }" +
"}, 600);";
在onPageFinished事件之后执行javascript稍微修复了三星Tab设备上的问题,如果js立即执行,它似乎没有准备就绪。我尝试了onload事件/ $(document).ready但仍然无法正常工作。等待600毫秒并不理想,但我已经花了足够的时间试图让它工作。
确保z-index大于iframe的z-index,最简单的方法是将zIndex设置为Integer.MAX_VALUE