WebView基础知识以及Androidx-WebKit的使用

news2024/12/23 15:05:15

文章目录

  • 摘要
  • WebView基础
    • 一、启动调整模式
    • 二、WebChromeClient
    • 三、WebViewClient
    • 四、WebSettings
    • 五、WebView和Native交互
  • Androidx-WebKit
    • 一、启动安全浏览服务
    • 二、设置代理
    • 三、安全的 WebView 和 Native 通信支持
    • 四、文件传递
    • 五、深色主题的支持
    • 六、JavaScript and WebAssembly执行引擎支持

摘要

文章主要分2部分:

  1. Webview的基础相关知识:如调试基础API、和原生交互等
  2. Androidx-WebKit 的使用: 如和原生的消息交互文件传递、以及启动安全浏览等

WebView基础

一、启动调整模式

在开发过程中,我们可以启用 WebView 的调试模式,以便在 Chrome DevTools 中查看 WebView 的内容、网络请求等信息。

WebView.setWebContentsDebuggingEnabled(true)

调试界面 chrome://inspect/#devices

在这里插入图片描述

二、WebChromeClient

WebChromeClient 是一个抽象基类,它的实例可以被传递给 WebView.setWebChromeClient() 方法,以处理与 JavaScript 交互和网页元素相关的事件。

2.1 WebChromeClient一进度相关

  • onProgressChanged(WebView view, int newProgress): 当页面加载进度改变时调用。newProgress参数表示当前页面加载的百分比。

2.2 WebChromeClient-标题、图标相关

  • onReceivedTitle(WebView view, String title): 当前页面的标题已经被接收到时调用。title参数是新的标题。
  • onReceivedIcon(WebView view, Bitmap icon): 当前页面的图标已经被接收到时调用。icon参数是新的图标。
  • onReceivedTouchIconUrl(WebView view, String url, boolean precomposed): 当网页的触摸图标URL被接收到时调用。url参数是图标的URL,precomposed参数表示图标是否已经被合成。

2.3 WebChromeClient-权限相关

  • onPermissionRequest(PermissionRequest request): 当网页请求一个权限时调用,例如摄像头、麦克风等。你可以在这个方法中处理权限请求。
  • onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback): 当网页请求获取地理位置权限时调用。origin参数是请求权限的网页的源,callback参数是用于设置权限的回调。
     override fun onPermissionRequest(request: PermissionRequest?) {
                    "onPermissionRequest".logD(WEB_TAG)
                    try {
                        request?.let {
                            kotlin.runCatching {
                                if (isVideo(request.resources)) {
                                    startRequestPermissions(permissions = arrayOf(permission.CAMERA, permission.RECORD_AUDIO)) {
                                        if (it.filter { !it.value }.isEmpty()) {
                                            request.grant(request.resources)
                                            request.origin
                                        }
                                    }
                                } else if (isOnlyAudio(request.resources)) {
                                    startRequestPermission(permission = permission.RECORD_AUDIO) {
                                        if (it) {
                                            request.grant(request.resources)
                                            request.origin
                                        }
                                    }
                                }
                            }
                        }
                    }catch (e :Exception){
                        e.message.logE(WEB_TAG)
                    }
                }

                private fun isVideo(resources: Array<String>): Boolean {
                    val strings = listOf(*resources)
                    return strings.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)
                }

                private fun isOnlyAudio(resources: Array<String>): Boolean {
                    val strings = listOf(*resources)
                    return !strings.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE) && strings.contains(PermissionRequest.RESOURCE_AUDIO_CAPTURE)
                }
            }

2.4 WebChromeClient-文件处理

  • onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams): 当网页需要用户选择文件时调用,例如HTML的元素被点击时。你可以在这个方法中打开一个文件选择器,并将用户选择的文件的URI通过filePathCallback返回。

2.5 WebChromeClient-弹窗、JS相关

  • onJsAlert(WebView view, String url, String message, JsResult result): 当JavaScript的alert()函数被调用时调用。message参数是alert()函数的参数。
  • onJsConfirm(WebView view, String url, String message, JsResult result): 当JavaScript的confirm()函数被调用时调用。message参数是confirm()函数的参数。
  • onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result): 当JavaScript的prompt()函数被调用时调用。message参数是prompt()函数的第一个参数,defaultValue参数是prompt()函数的第二个参数。
  • onConsoleMessage(ConsoleMessage consoleMessage): 当JavaScript的console.log()函数被调用时调用。consoleMessage参数包含了日志消息的详细信息。
  • onJsBeforeUnload(WebView view, String url, String message, JsResult result): 当JavaScript的beforeunload事件被触发时调用。message参数是beforeunload事件的返回值。
  • onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg): 当JavaScript的window.open()函数被调用时调用。你可以在这个方法中创建一个新的WebView,并将它通过resultMsg返回。
  • onCloseWindow(WebView window): 当JavaScript的window.close()函数被调用时调用。你可以在这个方法中关闭之前通过onCreateWindow创建的WebView。

2.6 WebChromeClient-视频相关

  • onShowCustomView(View view, CustomViewCallback callback): 当网页进入全屏模式时调用。在这种情况下,网页内容将不再在WebView中渲染,而是在传入的view中渲染。你应该将这个View添加到一个配置了WindowManager.LayoutParams.FLAG_FULLSCREEN标志的Window中,以实际全屏显示这个网页内容。
  • onHideCustomView(): 当网页退出全屏模式时调用。你应该隐藏自定义的View(之前传给onShowCustomView(View view, CustomViewCallback callback)的View)。在这个方法调用后,网页内容将再次在原来的WebView中渲染。
  • getDefaultVideoPoster(): 当视频元素不在播放状态时,它们由一个’poster’图像表示。可以通过HTML中的video标签的poster属性指定要使用的图像。如果该属性不存在,则使用默认的poster。这个方法允许ChromeClient提供默认的poster图像。
  • getVideoLoadingProgressView(): 获取在全屏视频缓冲期间显示的View。主应用程序可以覆盖此方法以提供包含旋转器或类似物的View。

三、WebViewClient

WebViewClient 是一个抽象基类,它的实例可以被传递给 WebView.setWebViewClient() 方法,以处理与网页加载和渲染相关的事件。

3.1 WebViewClient-重定向

  • shouldOverrideUrlLoading(WebView view, String url): 当 WebView 即将加载一个 URL 时调用。你可以在这个方法中决定是否要覆盖这个 URL 的加载,如果你想覆盖这个 URL 的加载,那么你应该返回 true,并在这个方法中进行你自己的处理,例如打开一个新的 Activity 来加载这个 URL。

3.2 WebViewClient-页面加载

  • onPageStarted(WebView view, String url, Bitmap favicon): 当网页开始加载时调用。url 参数是正在加载的网页的 URL。
  • onPageFinished(WebView view, String url): 当网页加载完成时调用。url 参数是刚刚加载完成的网页的 URL。
  • onLoadResource(WebView view, String url): 当 WebView 正在加载一个资源(例如图片或者 JavaScript 文件)时调用。url 参数是正在加载的资源的 URL。

3.3 WebViewClient-认证请求相关

  • onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm): 当 WebView 需要进行 HTTP 认证时调用。你可以在这个方法中处理认证请求,例如显示一个输入用户名和密码的对话框。
  • onReceivedLoginRequest(WebView view, String realm, @Nullable String account, String args): 当 WebView 需要进行自动登录时调用。你可以在这个方法中处理登录请求,例如从存储的账户信息中获取用户名和密码。

3.4 WebViewClient-其他

  • onReceivedError(WebView view, int errorCode, String description, String failingUrl): 当 WebView 加载网页时发生错误时调用。errorCode 参数是错误码,description 参数是错误描述,failingUrl 参数是发生错误的网页的 URL。
  • onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse): 当 WebView 接收到 HTTP 错误时调用。request 参数是发生错误的请求,errorResponse 参数是服务器的响应。
  • onReceivedSslError(WebView view, SslErrorHandler handler, SslError error): 当 WebView 加载的网页有 SSL 错误时调用。你可以在这个方法中处理 SSL 错误,例如显示一个对话框让用户决定是否要继续加载。
  • onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback): 当 WebView 访问一个被 Safe Browsing 判断为可能是恶意的网站时被调用。你可以在这个方法中处理这个事件,例如显示一个警告对话框,或者导航到一个安全的网页。callback 参数是一个 SafeBrowsingResponse,你可以调用它的 showInterstitial(boolean) 或 proceed(boolean) 方法来决定是否显示一个安全警告的插页广告,或者继续加载这个网页。
  • onFormResubmission(WebView view, Message dontResend, Message resend): 当 WebView 尝试重新提交一个表单,并且需要用户确认是否重新提交时调用。你可以在这个方法中处理这个事件,例如显示一个确认对话框。
  • onScaleChanged(WebView view, float oldScale, float newScale): 当 WebView 的缩放级别改变时调用。你可以在这个方法中处理缩放级别的改变,例如更新一个缩放级别的显示。
  • onUnhandledKeyEvent(WebView view, KeyEvent event): 当 WebView 收到一个未处理的按键事件时调用。你可以在这个方法中处理未处理的按键事件,例如实现自定义的按键处理。
  • doUpdateVisitedHistory(WebView view, String url, boolean isReload): 一个页面的访问历史记录被更新时,这个方法会被调用。

四、WebSettings

WebSettings 是一个类,它用于管理 WebView 的各种设置。你可以通过 WebView.getSettings() 方法获取到一个 WebSettings 实例,然后通过这个实例来配置 WebView 的设置。

以下是一些常用的 WebSettings 方法:

  • setJavaScriptEnabled(boolean enabled): 设置 WebView 是否支持 JavaScript。默认值为 false
  • setSupportZoom(boolean support): 设置 WebView 是否支持缩放。默认值为 false
  • setDisplayZoomControls(boolean enabled): 设置 WebView 是否显示缩放控件。默认值为 true
  • setBuiltInZoomControls(boolean enabled): 设置 WebView 是否使用内置的缩放机制。默认值为 false
  • setLoadWithOverviewMode(boolean overview): 设置 WebView 是否应该启用概览模式,即总是缩放内容以适应屏幕宽度。默认值为 false
  • setUseWideViewPort(boolean use): 设置 WebView 是否应该启用宽视图端口。默认值为 false
  • setJavaScriptCanOpenWindowsAutomatically(boolean allow): 设置 WebView 的 JavaScript 是否可以自动打开窗口。默认值为 false
  • setMediaPlaybackRequiresUserGesture(boolean require): 设置为 false,那么 WebView 中的音频和视频将会自动播放,不需要用户交互。
  • setLoadsImagesAutomatically(boolean flag): 用于设置 WebView 是否自动加载图片。 如果设置为 true,WebView 会自动加载网页中的图片。如果设置为 false,所有的图片都不会被加载,只有当 LOAD_CACHE_ELSE_NETWORK 或 LOAD_NO_CACHE 被使用时,才会加载。

WebSettings 提供了一些方法来管理 WebView 的缓存:

  1. setCacheMode(int mode): 设置 WebView 的缓存模式。可选的值有:
    • LOAD_DEFAULT: 默认的缓存模式。如果没有 Cache-ControlExpires 头,缓存会被存储,当资源过期时,WebView 会尝试从网络加载。如果没有网络,WebView 会从缓存加载。
    • LOAD_CACHE_ELSE_NETWORK: 只要缓存存在,即使过期也会从缓存加载。如果缓存不存在,WebView 会从网络加载。
    • LOAD_NO_CACHE: 不使用缓存,WebView 会从网络加载。
    • LOAD_CACHE_ONLY: 不从网络加载,只从缓存加载。
  2. setAppCacheEnabled(boolean enabled): 设置 WebView 是否启用应用缓存。默认值为 false。注意,你还需要通过 setAppCachePath 方法设置一个应用缓存的路径。
  3. setAppCachePath(String appCachePath): 设置应用缓存的路径。这个路径必须是可以让应用读写的。
  4. setAppCacheMaxSize(long appCacheMaxSize): 设置应用缓存的最大大小。
  5. setDatabaseEnabled(boolean enabled): 设置 WebView 是否启用数据库存储 API。默认值为 false
  6. setDomStorageEnabled(boolean enabled): 设置 WebView 是否启用 DOM 存储 API。默认值为 falsetrue可以使用 sessionStorage 和 localStorage 对象来存储和检索数据。。
  //设置Cookie
  fun setCookie(map: MutableMap<String, String>) {
        val cookieManager: CookieManager = CookieManager.getInstance()
        cookieManager.setAcceptCookie(true)
        map.onEach { entry ->
            cookieManager.setCookie(entry.key, entry.value)
        }
        cookieManager.flush()
    }
    /**
     * 给设置localStorage 设置数据
     */
    fun setLocalStorage(itmes: Map<String, String>) {
        val jsonBuf = StringBuilder()
        for (key in itmes.keys) {
            if (isNotEmpty(itmes[key])) {
                jsonBuf.append("localStorage.setItem('key', '")
                    .append(itmes[key])
                    .append("');")
            }
        }
        val info = jsonBuf.toString()
        if (isNotEmpty(info)) {
            webView.evaluateJavascript(info, null)
        }
    }

五、WebView和Native交互

WebView 和 Native 交互主要有两种方式:JavaScriptInterface 和 WebView.evaluateJavascript。

  1. JavaScriptInterface:这是一种将 Java 对象映射到 JavaScript 的方式。你可以创建一个 Java 对象,这个对象的公共方法可以在 JavaScript 中被调用。例如:
class JavaScriptInterface(private val context: Context) {
    @JavascriptInterface
    fun showToast(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }
}

val webView: WebView = findViewById(R.id.webview)
webView.addJavascriptInterface(JavaScriptInterface(this), "Android")

在上述代码中,我们创建了一个 JavaScriptInterface 类,并将其实例添加到了 WebView 中。

在 JavaScript 中:

Android.showToast(message);

WebView.evaluateJavascript:这是一种在 WebView 中执行 JavaScript 代码的方式。你可以使用这个方法来调用 JavaScript 函数,并获取返回值。例如:

webView.evaluateJavascript("document.title") { title ->
    Log.d("WebView", "Document title: $title")
}


Androidx-WebKit

dependencies {
    implementation("androidx.webkit:webkit:1.9.0")
}

这里下面就是WebKit对于的 WebView 的增强方法

一、启动安全浏览服务

    /**
         * Start safe browsing
         * 用于启动安全浏览服务。这个服务可以帮助 WebView 防止用户访问被认为是恶意的网站
         */
        fun startSafeBrowsing(){
            if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
                WebViewCompat.startSafeBrowsing(BaseKit.app) {
                    ("WebView.startSafeBrowsing isSuccess = $it").logI()
                }
            }
        }

二、设置代理

if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
    ProxyConfig proxyConfig = new ProxyConfig.Builder()
            .addProxyRule("localhost:7890") //添加要用于所有 URL 的代理
            .addProxyRule("localhost:1080") //优先级低于第一个代理,仅在上一个失败时应用
            .addDirect()                    //当前面的代理失败时,不使用代理直连
            .addBypassRule("www.baidu.com") //该网址不使用代理,直连服务
            .addBypassRule("*.cn")          //以.cn结尾的网址不使用代理
            .build();
    Executor executor = ...
    Runnable listener = ...
    ProxyController.getInstance().setProxyOverride(proxyConfig, executor, listener);

三、安全的 WebView 和 Native 通信支持

// App
    val myListener = object : WebViewCompat.WebMessageListener {

            /**
             * On post message
             *
             * @param view WebView
             * @param message js代码发送的消息
             * @param sourceOrigin 发送消息的网页地址
             * @param isMainFrame 是否是主页面,iFrame中的页面为false
             * @param replyProxy 回复消息的代理
             */
            override fun onPostMessage(view: WebView, message: WebMessageCompat, sourceOrigin: Uri, isMainFrame: Boolean, replyProxy: JavaScriptReplyProxy) {
            // do something about view, message, sourceOrigin and isMainFrame.
                }
    }
    val allowedOriginRules = allowedRules ?: setOf()
        WebViewCompat.addWebMessageListener(
        /* webView = */ webView,
        /* jsObjectName = */jsObjectName,
        /* allowedOriginRules = */ allowedOriginRules,
        /* listener = */myListener
    )

// Web page (in JavaScript)
myObject.onmessage = function(event) {
  // prints "Got it!" when we receive the app's response.
  console.log(event.data);
}
myObject.postMessage("I'm ready!");

四、文件传递

4.1 Native 传递文件给 WebView:

// App (in Java)
WebMessageListener myListener = new WebMessageListener() {
  @Override
  public void onPostMessage(WebView view, WebMessageCompat message, Uri sourceOrigin,
           boolean isMainFrame, JavaScriptReplyProxy replyProxy) {
    // Communication is setup, send file data to web.
    if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER)) {
      // Suppose readFileData method is to read content from file.
      byte[] fileData = readFileData("myFile.dat");
      replyProxy.postMessage(fileData);
    }
  }
}

// Web page (in JavaScript)
myObject.onmessage = function(event) {
  if (event.data instanceof ArrayBuffer) {
    const data = event.data;  // Received file content from app.
    const dataView = new DataView(data);
    // Consume file content by using JavaScript DataView to access ArrayBuffer.
  }
}
myObject.postMessage("Setup!");

4.2 WebView 传递文件给 Native:

// Web page (in JavaScript)
const response = await fetch('example.jpg');
if (response.ok) {
    const imageData = await response.arrayBuffer();
    myObject.postMessage(imageData);
}

// App (in Java)
WebMessageListener myListener = new WebMessageListener() {
  @Override
  public void onPostMessage(WebView view, WebMessageCompat message, Uri sourceOrigin,
           boolean isMainFrame, JavaScriptReplyProxy replyProxy) {
    if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
      byte[] imageData = message.getArrayBuffer();
      // do something like draw image on ImageView.
    }
  }
};

五、深色主题的支持

简单来说如果您想让 WebView 的内容和应用的主题相匹配,您应该始终定义深色主题并实现 prefers-color-scheme,而对于未定义 prefers-color-scheme 的页面,系统按照不同的策略选择算法生成或者显示默认页面。

六、JavaScript and WebAssembly执行引擎支持

JavascriptEngine 直接使用了 WebView 的 V8 实现,由于不用分配其他 WebView 资源所以资源消耗更低,并可以开启多个独立运行的沙箱环境,还针对传递大量数据做了优化。

if(!JavaScriptSandbox.isSupported()){
return;
}
//连接到引擎
ListenableFuture<JavaScriptSandbox> jsSandboxFuture =
               JavaScriptSandbox.createConnectedInstanceAsync(context);
//创建上下文 上下文间有简单的数据隔离
JavaScriptIsolate jsIsolate = jsSandbox.createIsolate();
//执行函数 && 获取结果
final String code = "function sum(a, b) { let r = a + b; return r.toString(); }; sum(3, 4)";
ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(code);
String result = resultFuture.get(5, TimeUnit.SECONDS);
Futures.addCallback(resultFuture,
       new FutureCallback<String>() {
           @Override
           public void onSuccess(String result) {
               text.append(result);
           }
           @Override
           public void onFailure(Throwable t) {
               text.append(t.getMessage());
           }
       },
       mainThreadExecutor); //Wasm运行
final byte[] hello_world_wasm = {
   0x00 ,0x61 ,0x73 ,0x6d ,0x01 ,0x00 ,0x00 ,0x00 ,0x01 ,0x0a ,0x02 ,0x60 ,0x02 ,0x7f ,0x7f ,0x01,
   0x7f ,0x60 ,0x00 ,0x00 ,0x03 ,0x03 ,0x02 ,0x00 ,0x01 ,0x04 ,0x04 ,0x01 ,0x70 ,0x00 ,0x01 ,0x05,
   0x03 ,0x01 ,0x00 ,0x00 ,0x06 ,0x06 ,0x01 ,0x7f ,0x00 ,0x41 ,0x08 ,0x0b ,0x07 ,0x18 ,0x03 ,0x06,
   0x6d ,0x65 ,0x6d ,0x6f ,0x72 ,0x79 ,0x02 ,0x00 ,0x05 ,0x74 ,0x61 ,0x62 ,0x6c ,0x65 ,0x01 ,0x00,
   0x03 ,0x61 ,0x64 ,0x64 ,0x00 ,0x00 ,0x09 ,0x07 ,0x01 ,0x00 ,0x41 ,0x00 ,0x0b ,0x01 ,0x01 ,0x0a,
   0x0c ,0x02 ,0x07 ,0x00 ,0x20 ,0x00 ,0x20 ,0x01 ,0x6a ,0x0b ,0x02 ,0x00 ,0x0b,
};
final String jsCode = "android.consumeNamedDataAsArrayBuffer('wasm-1').then(" +
       "(value) => { return WebAssembly.compile(value).then(" +
       "(module) => { return new WebAssembly.Instance(module).exports.add(20, 22).toString(); }" +
       ")})";
boolean success = js.provideNamedData("wasm-1", hello_world_wasm);
if (success) {
    FluentFuture.from(js.evaluateJavaScriptAsync(jsCode))
           .transform(this::println, mainThreadExecutor)
           .catching(Throwable.class, e -> println(e.getMessage()), mainThreadExecutor);
} else {
   // the data chunk name has been used before, use a different name
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1655578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

邮件大附件系统如何进行安全、高效的大附件发送?

邮件大附件系统是一套解决传统电子邮件系统&#xff0c;在发送大文件时遇到限制的解决方案。由于传统电子邮件系统通常对附件大小有限制&#xff0c;这使得发送大文件变得困难。邮件大附件系统通过各种技术手段&#xff0c;允许用户发送超过传统限制的大文件&#xff0c;通常在…

【随笔】Git 高级篇 -- 上传命令的参数 (下)git push(三十七)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

目标检测——低光可见光-红外配对数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

TypeScript学习日志-第二十四天(webpack构建ts+vue3)

webpack构建tsvue3 一、构建项目目录 如图&#xff1a; shim.d.ts 这个文件用于让ts识别.vue后缀的 后续会说 并且给 tsconfig.json 增加配置项 "include": ["src/**/*"] 二、基础构建 安装依赖 安装如下依赖&#xff1a; npm install webpack -D …

11.偏向锁原理及其实战

文章目录 偏向锁原理及其实战1.偏向锁原理2.偏向锁案例代码演示2.1.偏向锁案例代码2.2.1.无锁情况下状态2.1.2.偏向锁状态2.1.3.释放锁后的状态 2.2.偏向锁的膨胀和撤销2.2.1.偏向锁撤销的条件2.2.2.偏向锁的撤销 2.2.3.偏向锁的膨胀 2.3.全局安全点原理和偏向锁撤销性能问题2.…

在R的 RGui中,使用devtools 安装trajeR

创建于&#xff1a;2024.5.5 文章目录 1. 报错信息2. 尝试使用指定的清华镜像&#xff0c;没有解决3. 找到原因&#xff1a;官网把包删除了4. 尝试从网上下载&#xff0c;然后安装。没有成功5. 使用devtools安装5.1 尝试直接安装&#xff1a;install.packages("devtools&q…

OpenCV | 项目 | 虚拟绘画

OpenCV | 项目 | 虚拟绘画 捕捉摄像头 如果在虚拟机中运行&#xff0c;请确保虚拟机摄像头打开。 #include<opencv2/opencv.hpp>using namespace cv; using namespace std;int main() {VideoCapture cap(0);Mat img;while(1) {cap.read(img);imshow("Image"…

JetBrains的Java集成开发环境IntelliJ 2024.1版本在Windows/Linux系统的下载与安装配置

目录 前言一、IntelliJ在Windows安装二、IntelliJ在Linux安装三、Windows下使用配置四、Linux下使用配置总结 前言 ​ “ IntelliJ IDEA Ultimate是一款功能强大的Java集成开发环境&#xff08;IDE&#xff09;。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地…

labview技术交流-将时间字符串转换成时间格式

应用场景 我们在数据库中设计了datetime类型的字段&#xff0c;比如字段名就叫“保存时间”&#xff0c;当我们使用labview将表中数据读取出来后datetime类型的数据是以字符串的格式显示的。而我们想计算两条数据“保存时间”的间隔时间时&#xff0c;用字符串类型自然是没法计…

uniapp读取项目本地文件/json文件/txt文件

uniapp读取项目本地文件/json文件/txt文件 文件必须放在static目录下 方法&#xff1a; /*** 访问static里面的文件* param url 文件路径 必须在static目录下*/ function localFetch(url) {return new Promise((resolve, reject) > {plus.io.resolveLocalFileSystemURL(_ww…

OmniReader Pro mac激活版:智慧阅读新选择,开启高效学习之旅

在追求知识的道路上&#xff0c;一款优秀的阅读工具是不可或缺的。OmniReader Pro作为智慧阅读的新选择&#xff0c;以其独特的功能和卓越的性能&#xff0c;为您开启高效学习之旅。 OmniReader Pro具备高效的文本识别和处理技术&#xff0c;能够快速准确地提取文档中的关键信息…

PXE批量部署,一键安装配置多台Linux系统

目录 一、PXE批量部署的优点 二、搭建PXE远程安装服务器 1. 实验初始化设置 2. 一键安装软件包 3. 复制 vmlinuz、initrd.img、pxelinux.0文件 4. 配置PE启动菜单配置文件 5. 修改配置文件&#xff0c; 启动各个软件服务 6. kickstart自动应答文件修改启动菜单配置文件…

(一)Linux的vim编辑器的使用

一.vim编辑器 Vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但是还是有可以进步的地方。 vim 则可以说是程序开发者的一项很好用的工具。 二…

不抽象:Increase API 设计原则

原文&#xff1a;Increase - 2024.04.26 &#xff08;注&#xff1a;Increase 是一家提供金融技术服务的公司。&#xff09; API 资源是 API 的实体或对象。决定如何为这些实体命名和建模可以说是设计 API 最难也是最重要的部分。您所公开的资源组织了用户对您的产品如何工作…

什么才是正确的领域驱动实现架构?

作为一种系统建模方法&#xff0c;DDD同样涉及系统的体系架构设计。区别于分布式、事件驱动、消息总线等架构设计方法&#xff0c;DDD中的架构设计关注前面各章所介绍的聚合、实体、值对象、领域事件、应用服务以及资源库之间的交互方式和风格&#xff0c;并在设计思想上有其独…

揭秘设计师必备神器:情绪板是什么?

每个伟大的设计项目都从一点灵感开始。无论你是在设计网站、应用程序&#xff0c;还是想重新装修房子&#xff0c;情绪板都可以帮助你激发创造力&#xff0c;甚至情绪板也可以决定UI界面是否成功。本文将分享什么是情绪板&#xff0c;为什么需要情绪板&#xff0c;以及如何充分…

Linux下多线程相关概念

thread 1.什么是线程1.1 线程优缺点1.2 线程异常1.3 线程用途 2. 进程和线程区别3. 线程控制3.1 POSIX线程库3.2 pthread_create()3.3 线程ID3.4 线程ID地址空间布局pthread_self() 3.5 线程终止pthread_exit函数pthread_cancle函数 3.6 线程等待3.7 分离线程__thread修饰全局变…

OpenCV Radon变换探测直线(拉东变换)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Radon变换可以将原始图像中直线特征的处理问题转化为变换域图像中对应点特征的处理问题,其中对应特征点的横坐标表示原始图像的旋转角度,一般来讲原始图像中的噪声不会分布在直线的特征上。因此,Radon变换在探测…

Python实战开发及案例分析(12)—— 模拟退火算法

模拟退火算法&#xff08;Simulated Annealing&#xff09;是一种概率搜索算法&#xff0c;源自于金属退火过程。在金属退火中&#xff0c;通过缓慢降低温度&#xff0c;金属内部的原子能够从高能态逐步达到较低能态。模拟退火算法利用类似的原理&#xff0c;通过随机搜索和概率…

吉时利2400与Keithley 2450 SMU 数字源表区别?

Keithley SMU&#xff08;源测量单元&#xff09;数字源表是一种精密的电子测试设备&#xff0c;它结合了电流和电压源以及测量功能。这些设备被设计用于需要紧密耦合源和测量的测试应用中。Keithley 2400系列SMU数字源表提供了四象限精密电压和电流源/负载&#xff0c;以及触摸…