当前位置: 首页 > news >正文

Android WebView访问网页+自动播放视频+自动全屏+切换横屏

一、引言

        近期,我发现电视家、火星直播等在线看电视直播的软件都已倒闭,而我奶奶也再无法通过这些平台看电视了。她已六十多岁,快七十岁啦。这些平台的倒下对我来说其实没有多大的影响,但是对于文化不多的她而言,生活中却是少了一大乐趣。因为自己学过编程,所以我想帮她解决这个问题。她只听得懂白话,又最爱看“广东珠江台”,因此,我通过Android的编程技术,为她专门定制一款可以自动看广东珠江台的App,打开即用,免了点来点去的麻烦。虽说需求很小、只够她一人使用,但实现起来却并不简单呀。通过两天时间的深入钻研,最终我还是把这个小需求给实现了。为此编写一篇博客,如果日后自己还需要解决这样的问题时,我就直接ctrl+c加ctrl+v。当然,也希望这篇博客能够为你提供一些指导和帮助。

二、访问网页视频+自动播放的实现思路

        由于许多的m3u8链接都已经失效,现在看电视直播只能通过一些官方网页来实现,比如央视网等等。那么,访问网页的话是可以通过Android的WebView来实现,实现的方法非常简单,就是在Activity界面之中添加一个WebView空间,然后通过下面的代码来访问网页:

main_wv = findViewById(R.id.main_wv);
main_wv.setWebViewClient(new WebViewClient());
main_wv.setWebChromeClient(new WebChromeClient());
main_wv.loadUrl("https://***.***");

        但是这样的话,最多也只能够竖屏中观看视频,显示十分地有限,而且还不会自动播放,如图:

        所以,这里先介绍实现网页访问+自动播放的思路。WebView可以通过自定义的设置来控制它是否支持JavaScript脚本注入,即通过js来实现网页视频的自动播放。第一步是对WebView进行设置,而第二步是执行js自动播放视频的脚本,代码如下:

        设置WebView支持js脚本

WebSettings settings = main_wv.getSettings(); // main_wv为WebView控件
settings.setJavaScriptEnabled(true);

        执行js自动播放视频的脚本

String js = "javascript:";
js += "var videos = document.getElementsByTagName('video');";
js += "var video_last;";
js += "var video = videos[videos.length-1];";
js += "if (video != undefined && video != video_last) {";
{js += "video_last = video;";js += "function video_start() {";{js += "_VideoEnabledWebView.notifyVideoStart();";}js += "}";js += "video.addEventListener('play', video_start);";
}
js += "}";
main_wv.loadUrl(js);    // main_wv为WebView控件

        忘了介绍,该js脚本在什么时候执行了。这里补充一下,为了使得页面自动播放视频,需要重写一个WebViewClient类,类名可以随你定义,比如“MyWebViewClient”,然后重写public void onPageFinished(WebView view, String url)方法,如下:

@Override
public void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);String js = "javascript:";js += "var videos = document.getElementsByTagName('video');";js += "var video_last;";js += "var video = videos[videos.length-1];";js += "if (video != undefined && video != video_last) {";{js += "video_last = video;";js += "function video_start() {";{js += "_VideoEnabledWebView.notifyVideoStart();";}js += "}";js += "video.addEventListener('play', video_start);";}js += "}";main_wv.loadUrl(js); // main_wv为WebView控件
}

        至此,还请记得改

main_wv.setWebViewClient(new WebViewClient()); // main_wv为WebView控件

        为

main_wv.setWebViewClient(new MyWebViewClient()); // main_wv为WebView控件

        这样,在访问网页时,视频就可以自动播放啦。

三、网页自动全屏思路

        网页全屏的实现思路比较复杂,因为Android开发者的初衷是使网页设计者无法通过js的方式直接全屏地播放视频。也就是说,通过js注入的方式无法直接在WebView中实现网页的全屏播放。为什么呢?根据其他人的说法,这是因为Android开发者担心你的手机不小心访问到一个流氓网页,然后该网页直接全屏,使你的手机失控,被它播放的视频霸占许久、不能退出。我想了想,觉得这个理由倒是有些许合理的。因此执行js脚本注入无法直接在WebView中实现网页视频的全屏播放。

        但是网页全屏的实现是完全没有问题的。大体的思路是:重写WebChromeClient和WebView这两个类,通过重写其中的内部方法,在加载完网页后,再调用js脚本注入,进而触发视频的全屏播放。而触发视频的全屏播放的js脚本为:

"javascript:(" +
"function() { " +
" var videos = document.getElementsByTagName('video'); " +
" var video = videos[0]; " +
" if (!document.webkitFullScreen && video.webkitEnterFullscreen) {" +
" video.webkitEnterFullscreen(); " +
" } " +
" })()"

        由于实现的细节很多,再加上我只是简单地研究了一下,所以没法更详细地展开说说了。请大家看后边“全部代码”的章节部分,了解更多细节。

四、手机默认横屏思路

        手机默认横屏的思路实现起来非常简单,简单得不得了,只需要在Manifest.xml这个清单文件中对指定的Activity声明相关的属性即可。例如,用于播放的Activity为MainActivity,那么就这样设置:

<activity android:name=".MainActivity"android:theme="@android:style/Theme.NoTitleBar.Fullscreen"android:screenOrientation="landscape"android:configChanges="orientation|screenSize|keyboardHidden"android:hardwareAccelerated="true">
</activity>

        其中,最关键的两行代码为

android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape"

        上面一行说的是让app在手机上运行时不显示标题栏(这个可以看你个人需求,有的人喜欢留着,有的人喜欢去掉),而下面一行则是实现横屏的开关,landscape指的是风景,意为通过手机横屏的方式欣赏图片中的风景,以尽可能地使你更加清楚地目睹一张横向的风景图。

五、全部代码

        项目的代码目录,其中画横线部分是重点,我从创建项目到生成可运行且有效果的App只改动过这些文件。下面我将每个框中的文件中的代码罗列出来。

        AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="***.***.******"><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"android:hardwareAccelerated="true"android:theme="@android:style/Theme.NoTitleBar.Fullscreen"android:screenOrientation="landscape"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>

        MainActivity.java

package ***.***.***;import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;public class MainActivity extends Activity {VideoEnabledWebView mainWebView;RelativeLayout mainNonVideoRelativeLayout;ViewGroup mainVideoLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initView();         // initialize ui componentssetWebView();       // set webview's settingsloadVideoUrl();     // load video url}private void initView() {setContentView(R.layout.activity_main);mainNonVideoRelativeLayout = (RelativeLayout) findViewById(R.id.main_rl_non_video);mainVideoLayout = (ViewGroup)findViewById(R.id.main_rl_video);}@SuppressLint("SetJavaScriptEnabled")private void setWebView() {// create a webview instancemainWebView = new VideoEnabledWebView(this);mainWebView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));// add the webview instance to the main layoutmainNonVideoRelativeLayout.addView(mainWebView);// set general settings of webviewWebSettings settings = mainWebView.getSettings();settings.setAllowFileAccess(true);settings.setBuiltInZoomControls(false);settings.setJavaScriptEnabled(true);settings.setBuiltInZoomControls(false);// create a WebChromeClient instance and use it to set the webviewVideoEnabledWebChromeClient videoEnabledWebChromeClient = new VideoEnabledWebChromeClient(mainNonVideoRelativeLayout, mainVideoLayout,null, mainWebView);mainWebView.setWebChromeClient(videoEnabledWebChromeClient);// create a WebViewClient for webviewmainWebView.setWebViewClient(new WebViewClient(){@Overridepublic void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);// execute a javascript to automatically play the videoString js = "javascript:";js += "var videos = document.getElementsByTagName('video');";js += "var video_last;";js += "var video = videos[videos.length-1];";js += "if (video != undefined && video != video_last) {";{js += "video_last = video;";js += "function video_start() {";{js += "_VideoEnabledWebView.notifyVideoStart();";}js += "}";js += "video.addEventListener('play', video_start);";}js += "}";mainWebView.loadUrl(js);}});}private void loadVideoUrl() {mainWebView.loadUrl("https://******"); // your url that contains the video}
}

        activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><RelativeLayoutandroid:id="@+id/main_rl_non_video"android:layout_width="match_parent"android:layout_height="match_parent" ></RelativeLayout><RelativeLayoutandroid:id="@+id/main_rl_video"android:layout_width="match_parent"android:layout_height="match_parent" ></RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

        VideoEnabledWebChromeClient.java

package ***.***.***;import android.media.MediaPlayer;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.widget.FrameLayout;public class VideoEnabledWebChromeClient extends WebChromeClient implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {public interface ToggledFullscreenCallback {void toggledFullscreen(boolean fullscreen);}private View activityNonVideoView;private ViewGroup activityVideoView;private View loadingView;private VideoEnabledWebView webView;// Indicates if the video is being displayed using a custom view (typically full-screen)private boolean isVideoFullscreen;private FrameLayout videoViewContainer;private CustomViewCallback videoViewCallback;private ToggledFullscreenCallback toggledFullscreenCallback;/*** Never use this constructor alone.* This constructor allows this class to be defined as an inline inner class in which the user can override methods*/@SuppressWarnings("unused")public VideoEnabledWebChromeClient() {}/*** Builds a video enabled WebChromeClient.* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.* @param activityVideoView    A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.*/@SuppressWarnings("unused")public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView) {this.activityNonVideoView = activityNonVideoView;this.activityVideoView = activityVideoView;this.loadingView = null;this.webView = null;this.isVideoFullscreen = false;}/*** Builds a video enabled WebChromeClient.* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.* @param activityVideoView    A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.* @param loadingView          A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and not attached to a parent view.*/@SuppressWarnings("unused")public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView) {this.activityNonVideoView = activityNonVideoView;this.activityVideoView = activityVideoView;this.loadingView = loadingView;this.webView = null;this.isVideoFullscreen = false;}/*** Builds a video enabled WebChromeClient.* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.* @param activityVideoView    A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.* @param loadingView          A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and not attached to a parent view.* @param webView              The owner VideoEnabledWebView. Passing it will enable the VideoEnabledWebChromeClient to detect the HTML5 video ended event and exit full-screen.*                             Note: The web page must only contain one video tag in order for the HTML5 video ended event to work. This could be improved if needed (see Javascript code).*/@SuppressWarnings("unused")public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView, VideoEnabledWebView webView) {this.activityNonVideoView = activityNonVideoView;this.activityVideoView = activityVideoView;this.loadingView = loadingView;this.webView = webView;this.isVideoFullscreen = false;}/*** Indicates if the video is being displayed using a custom view (typically full-screen)* @return true it the video is being displayed using a custom view (typically full-screen)*/public boolean isVideoFullscreen() {return isVideoFullscreen;}/*** Set a callback that will be fired when the video starts or finishes displaying using a custom view (typically full-screen)* @param callback A VideoEnabledWebChromeClient.ToggledFullscreenCallback callback*/@SuppressWarnings("unused")public void setOnToggledFullscreen(ToggledFullscreenCallback callback) {this.toggledFullscreenCallback = callback;}@Overridepublic void onShowCustomView(View view, CustomViewCallback callback) {if (view instanceof FrameLayout) {// A video wants to be shownFrameLayout frameLayout = (FrameLayout) view;View focusedChild = frameLayout.getFocusedChild();// Save video related variablesthis.isVideoFullscreen = true;this.videoViewContainer = frameLayout;this.videoViewCallback = callback;// Hide the non-video view, add the video view, and show itactivityNonVideoView.setVisibility(View.INVISIBLE);activityVideoView.addView(videoViewContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));activityVideoView.setVisibility(View.VISIBLE);if (focusedChild instanceof android.widget.VideoView) {// android.widget.VideoView (typically API level <11)android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;// Handle all the required eventsvideoView.setOnPreparedListener(this);videoView.setOnCompletionListener(this);videoView.setOnErrorListener(this);} else {// Other classes, including:// - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 11-18)// - android.webkit.HTML5VideoFullScreen$VideoTextureView, which inherits from android.view.TextureView (typically API level 11-18)// - com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 19+)// Handle HTML5 video ended event only if the class is a SurfaceView// Test case: TextureView of Sony Xperia T API level 16 doesn't work fullscreen when loading the javascript belowif (webView != null && webView.getSettings().getJavaScriptEnabled() && focusedChild instanceof SurfaceView) {// Run javascript code that detects the video end and notifies the Javascript interfaceString js = "javascript:";js += "var _ytrp_html5_video_last;";js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";{js += "_ytrp_html5_video_last = _ytrp_html5_video;";js += "function _ytrp_html5_video_ended() {";{js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must match Javascript interface name and method of VideoEnableWebView}js += "}";js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";}js += "}";webView.loadUrl(js);}}// Notify full-screen changeif (toggledFullscreenCallback != null) {toggledFullscreenCallback.toggledFullscreen(true);}}}@Override// Available in API level 14+, deprecated in API level 18+public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) {onShowCustomView(view, callback);}@Override// This method should be manually called on video end in all cases because it's not always called automatically.// This method must be manually called on back key press (from this class' onBackPressed() method).public void onHideCustomView() {if (isVideoFullscreen) {// Hide the video view, remove it, and show the non-video viewactivityVideoView.setVisibility(View.INVISIBLE);activityVideoView.removeView(videoViewContainer);activityNonVideoView.setVisibility(View.VISIBLE);// Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium.")) {videoViewCallback.onCustomViewHidden();}// Reset video related variablesisVideoFullscreen = false;videoViewContainer = null;videoViewCallback = null;// Notify full-screen changeif (toggledFullscreenCallback != null) {toggledFullscreenCallback.toggledFullscreen(false);}}}@Override// Video will start loadingpublic View getVideoLoadingProgressView() {if (loadingView != null) {loadingView.setVisibility(View.VISIBLE);return loadingView;} else {return super.getVideoLoadingProgressView();}}@Override// Video will start playing, only called in the case of android.widget.VideoView (typically API level <11)public void onPrepared(MediaPlayer mp) {if (loadingView != null) {loadingView.setVisibility(View.GONE);}}@Override// Video finished playing, only called in the case of android.widget.VideoView (typically API level <11)public void onCompletion(MediaPlayer mp) {onHideCustomView();}@Override// Error while playing video, only called in the case of android.widget.VideoView (typically API level <11)public boolean onError(MediaPlayer mp, int what, int extra) {return false; // By returning false, onCompletion() will be called}/*** Notifies the class that the back key has been pressed by the user.* This must be called from the Activity's onBackPressed(), and if it returns false, the activity itself should handle it. Otherwise don't do anything.* @return Returns true if the event was handled, and false if was not (video view is not visible)*/@SuppressWarnings("unused")public boolean onBackPressed() {if (isVideoFullscreen) {onHideCustomView();return true;} else {return false;}}
}

        VideoEnabledWebView.java

package ***.***.***;import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebView;import java.util.Map;public class VideoEnabledWebView extends WebView {public class JavascriptInterface {@android.webkit.JavascriptInterface@SuppressWarnings("unused")// Must match Javascript interface method of VideoEnabledWebChromeClientpublic void notifyVideoEnd() {// This code is not executed in the UI thread, so we must force that to happennew Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {if (videoEnabledWebChromeClient != null) {videoEnabledWebChromeClient.onHideCustomView();}}});}@android.webkit.JavascriptInterface@SuppressWarnings("unused")// Must match Javascript interface method of VideoEnabledWebChromeClientpublic void notifyVideoStart() {// This code is not executed in the UI thread, so we must force that to happennew Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {loadUrl("javascript:(" +"function() { " +" var videos = document.getElementsByTagName('video'); " +" var video = videos[0]; " +" if (!document.webkitFullScreen && video.webkitEnterFullscreen) {" +" video.webkitEnterFullscreen(); " +" } " +" })()");}});}}private VideoEnabledWebChromeClient videoEnabledWebChromeClient;private boolean addedJavascriptInterface;@SuppressWarnings("unused")public VideoEnabledWebView(Context context) {super(context);addedJavascriptInterface = false;}@SuppressWarnings("unused")public VideoEnabledWebView(Context context, AttributeSet attrs) {super(context, attrs);addedJavascriptInterface = false;}@SuppressWarnings("unused")public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);addedJavascriptInterface = false;}/*** Indicates if the video is being displayed using a custom view (typically full-screen)** @return true it the video is being displayed using a custom view (typically full-screen)*/@SuppressWarnings("unused")public boolean isVideoFullscreen() {return videoEnabledWebChromeClient != null && videoEnabledWebChromeClient.isVideoFullscreen();}/*** Pass only a VideoEnabledWebChromeClient instance.*/@Override@SuppressLint("SetJavaScriptEnabled")public void setWebChromeClient(WebChromeClient client) {getSettings().setJavaScriptEnabled(true);if (client instanceof VideoEnabledWebChromeClient) {this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client;}super.setWebChromeClient(client);}@Overridepublic void loadData(String data, String mimeType, String encoding) {addJavascriptInterface();super.loadData(data, mimeType, encoding);}@Overridepublic void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) {addJavascriptInterface();super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);}@Overridepublic void loadUrl(String url) {super.loadUrl(url);addJavascriptInterface();}@Overridepublic void loadUrl(String url, Map<String, String> additionalHttpHeaders) {addJavascriptInterface();super.loadUrl(url, additionalHttpHeaders);}@SuppressLint("AddJavascriptInterface")private void addJavascriptInterface() {if (!addedJavascriptInterface) {// Add javascript interface to be called when the video ends (must be done before page load)// Must match Javascript interface name of VideoEnabledWebChromeClientaddJavascriptInterface(new JavascriptInterface(), "_VideoEnabledWebView");addedJavascriptInterface = true;}}
}

六、效果

        打开App之后,经过2s的时间(对于个人而言,2s是可接受的等待时间)直接视频全屏播放

        但我发现url有时候不是特别稳定,所以有时候看不了,并建议使用电脑端访问。

七、参考资料

1.如何在android WebView中全屏播放HTML5视频?

2.android webview播放视频自动全屏

八、声明

上述代码仅限个人的学习使用,请勿用于商业用途,请勿非法使用,谢谢。

相关文章:

Android WebView访问网页+自动播放视频+自动全屏+切换横屏

一、引言 近期&#xff0c;我发现电视家、火星直播等在线看电视直播的软件都已倒闭&#xff0c;而我奶奶也再无法通过这些平台看电视了。她已六十多岁&#xff0c;快七十岁啦。这些平台的倒下对我来说其实没有多大的影响&#xff0c;但是对于文化不多的她而言&#xff0c;生活中…...

php PhpSpreadsheet 读取日期变数字问题解决

问题描述&#xff1a; 使用PhpSpreadsheet 读取表格数据&#xff0c;日期格式读取后变成数字&#xff0c;如下图&#xff1a; 解决方案&#xff1a; $cell $sheet->getCell(H . $row)->getValue(); $toTimestamp \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimes…...

前端架构: 脚手架包管理工具之lerna的全流程开发教程

Lerna 1 &#xff09;文档 Lerna 文档 https://www.npmjs.com/package/lernahttps://lerna.js.org [请直达这个链接] 使用 Lerna 帮助我们做包管理&#xff0c;并不复杂&#xff0c;中间常用的命令并不是很多这里是命令直达&#xff1a;https://lerna.js.org/docs/api-referen…...

[安洵杯 2019]easy_serialize_php1

打开题目 题目源码&#xff1a; <?php$function $_GET[f];function filter($img){$filter_arr array(php,flag,php5,php4,fl1g);$filter /.implode(|,$filter_arr)./i;return preg_replace($filter,,$img); }if($_SESSION){unset($_SESSION); }$_SESSION["user&q…...

【前端素材】推荐优质在线通用果蔬商城电商网页eStore平台模板(附源码)

一、需求分析 1、系统定义 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。它将不同种类的新鲜水果、蔬菜、干果、坚果等聚集在一起&#xff0c;为消费者提供方便、快捷的购物渠道。 2、功能需求 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。…...

开源软件的商业模式探析:开放与盈利的平衡

写在开头 开源软件的概念和应用已经成为了现代科技领域中的一个重要组成部分。然而&#xff0c;虽然开源软件的价值和影响力得到了广泛认可&#xff0c;但如何在开放的环境中找到商业盈利的平衡却是一个颇具挑战性的问题。本文将深入探讨开源软件的商业模式&#xff0c;从基本…...

使用全局事件总线实现任意组件间的通讯

本文以vue2中爷孙组件通讯为例&#xff0c;需求是点击孙组件的按钮&#xff0c;实现关闭爷组件的弹窗。 全局事件总线是通过Vue实例的事件系统来实现组件之间的通讯&#xff0c;可以方便地在任何组件中进行事件的触发和监听。 以下是使用全局事件总线实现爷孙组件通讯的步骤&a…...

文件基础和文件fd

文章目录 预备知识C语言的文件接口系统调用文件fd 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 预备知识 我们平时说文件就是说文件里…...

3dgs学习(二)—— 3d高斯与协方差矩阵及其几何意义

协方差矩阵与3d高斯 3d高斯与椭球与协方差矩阵 3d高斯&#xff0c;及3维空间内的正态分布。 通过一元正态分布的坐标系图像不难想象&#xff0c;3维空间中的正态分布点集中在一片椭球空间中&#xff0c;各方向长轴取决于各方向正态分布的方差。 而协方差矩阵通过计算多元之…...

ZStack Cube超融合入选IDC《中国超融合基础架构市场评估》报告

近日&#xff0c;IDC发布了《中国超融合基础架构市场评估&#xff0c;2023》。IDC针对中国超融合基础架构市场的发展现状展开了调研&#xff0c;明确了最终用户构建融合型云平台的痛点和难点&#xff0c;阐述了市场中各技术服务提供商的服务方案和优势&#xff0c;并对未来中国…...

每日一题——LeetCode1556.千位分隔符

方法一 个人方法&#xff1a; 把n转为字符串&#xff0c;逆序遍历n&#xff0c;把n的每个元素加入res&#xff0c;每三次加入.&#xff0c;最后将res翻转再转为字符串即为符合题目要求的结果 var thousandSeparator function(n) {nlet res[],lenn.length-1for(let ilen;i>…...

8.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-游戏底层功能对接类GameProc的实现

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;通过逆向分析确定游戏明文接收数据过程 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;bcf7559184863febdcad819e48aa…...

Redis冲冲冲——事务支持,AOF和RDB持久化

目录 引出Redis事务支持&#xff0c;AOF和RDB持久化1、Redis的事务支持2、Redis的持久化 Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 Redis冲冲冲——事务支持&#xff0c;AOF和RDB持久化 Redis事务支持&#xff0c;AOF和…...

路由菜单路径匹配方法

优化路由菜单路径匹配算法&#xff1a;实现获取整条线路的路径 引言 在前端开发中&#xff0c;路由菜单的路径匹配是一个常见的需求。我们经常需要根据给定的路径&#xff0c;找到对应的菜单项&#xff0c;并获取整条线路的路径。本文将介绍一个优化的路由菜单路径匹配算法&…...

设计模式浅析(九) ·模板方法模式

设计模式浅析(九) 模板方法模式 日常叨逼叨 java设计模式浅析&#xff0c;如果觉得对你有帮助&#xff0c;记得一键三连&#xff0c;谢谢各位观众老爷&#x1f601;&#x1f601; 模板方法模式 概念 模板方法模式&#xff08;Template Method Pattern&#xff09;在Java中是…...

无用工作、UBI与AI

有些隐晦和黑暗的事实无法陈述&#xff0c;因为任何的系统中“无用”的结局都是被无情的抛弃和淘汰&#xff0c;AI监督下的人类结局更是如此。 什么是无用工作&#xff1f; 无用无效工作通常指的是那些看似忙碌但实际上对社会或个人没有实质性贡献的工作。这类工作可能包括以下…...

【监控】grafana图表使用快速上手

目录 1.前言 2.连接 3.图表 4.job和path 5.总结 1.前言 上一篇文章中&#xff0c;我们使用spring actuatorPrometheusgrafana实现了对一个spring boot应用的可视化监控。 【监控】Spring BootPrometheusGrafana实现可视化监控-CSDN博客 其中对grafana只是打开了一下&am…...

Django常用命令

一、新建一个新项目 django-admin startproject project_name二、新建一个app 在Django中的一个app代表一个功能模块。开发者可以将不同功能的模块放在不同的app中, 方便代码的复用。 python manage.py startapp appa_name三、数据迁移(更新数据库) 编写好了Model后&#x…...

【center-loss 中心损失函数】 原理及程序解释(更新中)

文章目录 前言问题引出open-set问题抛出 解决方法softmax函数、softmax-loss函数解决代码&#xff08;center_loss.py&#xff09;原理程序解释 如何梯度更新首先了解一下基本的梯度下降算法然后 前言 学习一下&#xff1a; 中心损失函数&#xff0c;用于用于深度人脸识别的特…...

什么是 HTTPS 证书?作用是什么?

HTTPS 证书&#xff0c;即超文本传输安全协议证书&#xff08;Hypertext Transfer Protocol Secure&#xff09;&#xff0c;是网站安全的关键组成部分。它通过 SSL/TLS 加密协议&#xff0c;确保用户与网站之间的数据传输是加密和安全的。 什么是 HTTPS 证书&#xff1f; HT…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...