实现一个优雅的 jsBridge 方案

实现一个优雅的 jsBridge 方案

在 iOS 项目中,有时需要实现 JavaScript 和 Native 代码之间的通信。本文介绍一种优雅的 jsBridge 实现方案,支持互相调用和回调机制,并附带详细的代码和注释。

步骤 1: 定义桥接协议

首先,定义一个通用的消息格式,用于传递方法名和参数,以及回调标识符。例如:

{"method": "showAlert","params": {"title": "Hello","message": "This is a message from JavaScript"},"callbackId": "callback_1"
}

步骤 2: 设置 WebView

我们需要设置 WKWebView 并配置消息处理器,以处理来自 JavaScript 的消息。

import WebKitclass ViewController: UIViewController, WKScriptMessageHandler {var webView: WKWebView!var callbacks: [String: (Any?) -> Void] = [:]override func viewDidLoad() {super.viewDidLoad()// 设置 WKWebView 配置let contentController = WKUserContentController()// 在 WKWebView 中注册一个名为 jsBridge 的消息处理器,以便接收和处理从 JavaScript 发送到 Native 代码的消息。contentController.add(self, name: "jsBridge")let config = WKWebViewConfiguration()config.userContentController = contentController// 初始化 WKWebViewwebView = WKWebView(frame: self.view.bounds, configuration: config)self.view.addSubview(webView)// 加载网页if let url = URL(string: "https://your-web-page-url.com") {webView.load(URLRequest(url: url))}}// 处理从 JavaScript 发送的消息func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {guard let messageBody = message.body as? [String: Any],let method = messageBody["method"] as? String,let params = messageBody["params"] as? [String: Any],let callbackId = messageBody["callbackId"] as? String else {return}handleJSMethod(method, params: params, callbackId: callbackId)}// 处理具体的 JavaScript 调用的方法func handleJSMethod(_ method: String, params: [String: Any], callbackId: String) {if method == "showAlert" {if let title = params["title"] as? String,let message = params["message"] as? String {showAlert(title: title, message: message) { result inself.callJSCallback(callbackId: callbackId, result: result)}}}// 处理其他方法}// 显示警告框,并在完成后调用回调func showAlert(title: String, message: String, completion: @escaping (Any?) -> Void) {let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ incompletion(["status": "OK"])}))self.present(alert, animated: true, completion: nil)}// 调用 JavaScript 回调函数func callJSCallback(callbackId: String, result: Any?) {// 将结果转换为 JSON 格式,并进行 Base64 编码let jsonResult = (try? JSONSerialization.data(withJSONObject: result ?? [:]))?.base64EncodedString() ?? ""// 构建 JavaScript 代码,调用回调函数 (jsBridge,_invokeCallback 都是通过注入 JS 代码实现的)let jsCode = "window.jsBridge._invokeCallback('\(callbackId)', '\(jsonResult)')"webView.evaluateJavaScript(jsCode, completionHandler: nil)}deinit {// 移除消息处理器以避免内存泄漏webView.configuration.userContentController.removeScriptMessageHandler(forName: "jsBridge")}
}

步骤 3: 注入 JS 代码

在网页加载完成后注入 JavaScript 代码,使得网页可以调用 Native 方法并处理回调。为了避免重复注入,我们在 JavaScript 中添加一个标志变量。

override func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {let jsCode = """(function() {if (window.jsBridgeInjected) {return;}window.jsBridgeInjected = true;window.jsBridge = {callbacks: {},// 调用 Native 方法callNative: function(method, params, callback) {const callbackId = 'cb_' + (new Date()).getTime();this.callbacks[callbackId] = callback;// 能够这样调用的原因是:在 WKWebView 中进行过配置 ->`contentController.add(self, name: "jsBridge")`window.webkit.messageHandlers.jsBridge.postMessage({method: method,params: params,callbackId: callbackId});},// Native 调用的回调方法_invokeCallback: function(callbackId, result) {if (this.callbacks[callbackId]) {const resultObj = JSON.parse(atob(result));this.callbacks[callbackId](resultObj);delete this.callbacks[callbackId];}}};})();"""webView.evaluateJavaScript(jsCode, completionHandler: nil)
}

怎样使用 ?

在 JS 中调用 Native 方法并处理回调

在你的网页 JavaScript 代码中,通过 jsBridge.callNative 方法调用 Native 方法,并处理回调:

function showAlert() {jsBridge.callNative("showAlert", { title: "Hello", message: "This is a message from JavaScript" }, function(result) {console.log("Alert closed with status:", result.status);});
}

更完整的代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JSBridge Example</title><script>function showAlert() {if (window.jsBridge && window.jsBridge.callNative) {jsBridge.callNative("showAlert", { title: "Hello", message: "This is a message from JavaScript" }, function(result) {console.log("Alert closed with status:", result.status);});} else {console.error('jsBridge or callNative is not defined');}}</script>
</head>
<body><h1>JSBridge Example</h1><button onclick="showAlert()">Show Alert</button>
</body>
</html>

Native 调用 JavaScript 方法

假设我们有一个 JavaScript 函数 displayMessage,用于显示消息。我们可以通过以下方式从 Native 调用它:

JavaScript 代码

function displayMessage(params) {alert(params.message);
}

为了确保 displayMessage 函数能够从 Native 中调用

  • 它需要在被调用时,定义所在文件已经加载完成,displayMessage 已被成功定义好;
  • 可被全局访问,这意味着你需要在 JavaScript 代码的全局作用域中定义该函数;

示例实现

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JSBridge Example</title><script>function displayMessage(params) {alert(params.message);}(function() {if (window.jsBridgeInjected) {return;}window.jsBridgeInjected = true;window.jsBridge = {callbacks: {},// 调用 Native 方法callNative: function(method, params, callback) {const callbackId = 'cb_' + (new Date()).getTime();this.callbacks[callbackId] = callback;window.webkit.messageHandlers.jsBridge.postMessage({method: method,params: params,callbackId: callbackId});},// Native 调用的回调方法_invokeCallback: function(callbackId, result) {if (this.callbacks[callbackId]) {const resultObj = JSON.parse(atob(result));this.callbacks[callbackId](resultObj);delete this.callbacks[callbackId];}}};})();</script>
</head>
<body><h1>JSBridge Example</h1>
</body>
</html>

通过在网页的全局作用域中定义 JavaScript 函数,并确保在网页加载完成后调用这些函数,可以实现从 Native 代码调用 JavaScript 函数。这种方式可以确保函数在需要时已经定义并可用。


为了让 Native 代码能够调用 JavaScript 方法,我们需要在 Swift 代码中添加调用 JavaScript 函数的功能。以下是如何在 Native 代码中调用 JavaScript 的示例:

// 调用 JavaScript 方法
func callJSFunction(functionName: String, params: [String: Any]) {// 将参数转换为 JSON 格式let jsonData = try? JSONSerialization.data(withJSONObject: params)let jsonString = String(data: jsonData!, encoding: .utf8)// 构建 JavaScript 代码let jsCode = "\(functionName)(\(jsonString!))"// 执行 JavaScript 代码webView.evaluateJavaScript(jsCode, completionHandler: { (result, error) inif let error = error {print("Error calling JS function: \(error)")} else {print("JS function called successfully with result: \(String(describing: result))")}})
}
示例:从 Native 调用 JavaScript

Swift 代码

// 调用 JavaScript 函数
callJSFunction(functionName: "displayMessage", params: ["message": "Hello from Native!"])

总结

通过以上步骤和代码示例,你可以实现一个优雅的 jsBridge,使 JavaScript 和 Native 代码之间可以互相调用并支持回调机制。这种实现方式可以确保数据传输的稳定性和安全性,同时提升应用的交互能力。


技术细节

异步执行的设计哲学

设计 evaluateJavaScript (Native端调用) 和 window.webkit.messageHandlers.jsBridge.postMessage (Js端调用) 为异步执行的主要原因是为了确保应用的响应性和用户体验,同时避免阻塞主线程或 JavaScript 执行。这种设计带来了多方面的好处,以下是详细的解释。

1. 保证主线程的响应性

避免 UI 卡顿

在 iOS 应用中,主线程(也称为 UI 线程)负责处理用户界面更新和响应用户交互。如果在主线程上执行耗时操作,例如等待 JavaScript 代码执行或处理消息,会导致界面卡顿,影响用户体验。

示例

webView.evaluateJavaScript("heavyComputation()") { (result, error) in// 回调处理结果
}

如果 evaluateJavaScript 是同步执行的,那么在 heavyComputation() 完成之前,主线程会被阻塞,导致应用无法响应用户的操作。

异步执行确保流畅的用户体验

通过异步执行,evaluateJavaScriptpostMessage 会立即返回,允许主线程继续处理其他任务,如用户界面更新和交互。这确保了应用的流畅性和响应性。

2. 提升性能和效率

并行处理

异步执行允许并行处理多个任务。例如,WebView 可以同时加载页面内容和执行 JavaScript 代码,而不会相互阻塞。这种并行处理提高了整体性能和效率。

示例

window.webkit.messageHandlers.jsBridge.postMessage({ method: "doWork" });
// 同时执行其他任务
console.log("Message sent, continue executing other tasks.");

3. 防止死锁和资源争用

避免死锁

同步调用可能会导致死锁,特别是在跨语言调用时。如果 JavaScript 和 Native 代码相互等待对方完成操作,可能会导致死锁,导致应用无法继续执行。

管理资源争用

异步执行可以更好地管理资源争用,避免长时间占用某些资源(如网络、文件系统等),从而提高系统的稳定性和可靠性。

4. 提供更好的错误处理机制

异步回调处理错误

异步执行允许通过回调机制处理错误和异常。这样可以在不阻塞主线程的情况下,优雅地处理和记录错误,确保应用的健壮性。

示例

webView.evaluateJavaScript("document.title") { (result, error) inif let error = error {print("JavaScript execution failed with error: \(error)")} else if let result = result {print("JavaScript execution result: \(result)")}
}

5. 提高开发效率和代码可维护性

简化代码逻辑

异步执行通过回调或 Promises 简化了代码逻辑,避免了复杂的同步处理和锁定机制。这提高了代码的可读性和可维护性。

示例

function sendMessageToNative() {console.log("Sending message to native code");window.webkit.messageHandlers.jsBridge.postMessage({method: "showAlert",params: {title: "Hello",message: "This is a message from JavaScript"}});console.log("Message sent to native code");
}

总结

设计 evaluateJavaScriptwindow.webkit.messageHandlers.jsBridge.postMessage 为异步执行,是为了确保应用的响应性和用户体验,提升性能和效率,防止死锁和资源争用,提供更好的错误处理机制,并提高开发效率和代码可维护性。通过异步执行,这些方法可以立即返回,避免阻塞主线程或 JavaScript 执行,从而确保应用在进行跨语言调用时的流畅性和稳定性。

谨记:didReceiveMessage 是在 main 线程上调用执行的

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) 方法是在主线程上被调用的。这确保了所有的 UI 更新和操作都在主线程上完成,保持线程安全和 UI 的一致性。为了避免在处理消息时阻塞主线程,可以将耗时操作放到后台线程中执行,并在需要时回到主线程更新 UI。通过这种方式,可以确保应用的响应性和用户体验。


在实际开发中,jsBridge 会存在性能问题么 ?怎么监控 ?

在实际开发中,jsBridge 的性能问题主要来自于以下几个方面:

  1. 频繁的跨语言调用:每次 JavaScript 和 Native 代码之间的调用都涉及到上下文切换,这可能会导致性能瓶颈,尤其是在频繁调用的情况下。
  2. 数据传输开销:较大的数据通过 jsBridge 传输可能会影响性能,因为需要进行序列化和反序列化操作。
  3. 线程阻塞:某些操作可能会在主线程上执行,导致界面卡顿或阻塞。
  4. 复杂的业务逻辑:如果 jsBridge 处理的业务逻辑过于复杂,也可能影响整体性能。

性能监控

为了监控和优化 jsBridge 的性能,可以采用以下方法:

  1. 日志记录:在 jsBridge 的每次调用前后记录时间戳,以计算调用的耗时。

  2. 性能分析工具:使用系统自带或第三方性能分析工具,如 Xcode 的 Instruments,来监测 CPU 使用率、内存占用和线程活动等指标。

  3. 定期分析和优化:通过定期的性能分析和代码审查,识别和优化性能瓶颈。

具体实现

1. 日志记录

在每次 jsBridge 调用前后记录时间戳,并计算耗时:

JavaScript 端

(function() {window.jsBridge = {callbacks: {},callNative: function(method, params, callback) {const startTime = Date.now();const callbackId = 'cb_' + startTime;this.callbacks[callbackId] = (result) => {const endTime = Date.now();console.log(`Call to ${method} took ${endTime - startTime}ms`);callback(result);};window.webkit.messageHandlers.jsBridge.postMessage({method: method,params: params,callbackId: callbackId});},_invokeCallback: function(callbackId, result) {if (this.callbacks[callbackId]) {this.callbacks[callbackId](result);delete this.callbacks[callbackId];}}};
})();

Swift 端

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {let startTime = Date().timeIntervalSince1970guard let messageBody = message.body as? [String: Any],let method = messageBody["method"] as? String,let params = messageBody["params"] as? [String: Any],let callbackId = messageBody["callbackId"] as? String else {return}handleJSMethod(method, params: params, callbackId: callbackId)let endTime = Date().timeIntervalSince1970print("Call to \(method) took \((endTime - startTime) * 1000)ms")
}
2. 使用性能分析工具

Xcode Instruments

  1. 启动 Instruments:打开 Xcode,选择菜单栏中的 Xcode > Open Developer Tool > Instruments
  2. 选择模板:选择合适的模板,如 Time Profiler 或 Activity Monitor。
  3. 运行应用:通过 Instruments 运行你的应用,开始性能监测。
  4. 分析结果:查看和分析 CPU 使用率、内存占用和线程活动,找出性能瓶颈。
3. 定期分析和优化

定期进行代码审查和性能分析,找出性能瓶颈,并进行优化。例如:

  • 减少频繁调用:合并多次调用,减少跨语言调用的次数。
  • 优化数据传输:通过压缩或分批传输数据,减少数据传输的开销。
  • 优化线程处理:避免在主线程上执行耗时操作,将其放到后台线程处理。

小结

jsBridge 的性能问题主要来自于频繁的跨语言调用、数据传输开销、线程阻塞和复杂的业务逻辑。通过日志记录、使用性能分析工具和定期分析优化,可以有效监控和提升 jsBridge 的性能。


使用 WKScriptMessage (实现 Native JavaScript 的交互)与使用 JavaScriptCore 有什么不一样 ?

在 iOS 开发中,实现 Native 和 JavaScript 交互的主要方式有两种:WKScriptMessageJavaScriptCore。它们在功能、使用场景和性能上有一些明显的不同。

WKScriptMessage

WKScriptMessage 是 WKWebView 的一种机制,允许 JavaScript 发送消息给 Native 代码。它是通过 WKUserContentController 来添加消息处理器,并通过 WKScriptMessageHandler 来处理这些消息。

特点
  1. 现代化

    • 适用于 WKWebView,这是苹果推荐的现代 WebView 实现,性能和安全性都优于 UIWebView
  2. 简单易用

    • 配置和使用相对简单,只需要添加消息处理器并处理消息。
  3. 安全性

    • 通过消息传递,避免了直接调用 Native 方法的安全隐患。
使用示例

Swift 端

import WebKitclass ViewController: UIViewController, WKScriptMessageHandler {var webView: WKWebView!override func viewDidLoad() {super.viewDidLoad()let contentController = WKUserContentController()contentController.add(self, name: "jsBridge")let config = WKWebViewConfiguration()config.userContentController = contentControllerwebView = WKWebView(frame: self.view.bounds, configuration: config)self.view.addSubview(webView)if let url = URL(string: "https://your-web-page-url.com") {webView.load(URLRequest(url: url))}}func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {if message.name == "jsBridge" {if let body = message.body as? [String: Any] {handleJSMessage(body)}}}func handleJSMessage(_ message: [String: Any]) {// 处理来自 JavaScript 的消息}deinit {webView.configuration.userContentController.removeScriptMessageHandler(forName: "jsBridge")}
}

JavaScript 端

function sendMessageToNative() {window.webkit.messageHandlers.jsBridge.postMessage({method: "showAlert",params: {title: "Hello",message: "This is a message from JavaScript"}});
}

JavaScriptCore

JavaScriptCore 是 iOS 上的一个框架,提供了一个 JavaScript 引擎,允许在 Native 代码中直接执行 JavaScript 代码,并在 JavaScript 中调用 Native 方法。它主要用于 UIWebView 或不使用 WebView 的纯 JavaScript 处理。

特点
  1. 直接调用

    • 允许直接在 Native 代码中执行 JavaScript 代码,并获取结果。
    • 允许在 JavaScript 中直接调用 Native 方法。
  2. 高级功能

    • 支持更复杂的 JavaScript 操作,例如创建和操作 JSContext、JSValue 等。
  3. 灵活性

    • 适用于需要复杂 JavaScript 处理的场景。
使用示例

Swift 端

import JavaScriptCoreclass ViewController: UIViewController {var jsContext: JSContext!override func viewDidLoad() {super.viewDidLoad()jsContext = JSContext()// 定义一个 Native 方法,供 JavaScript 调用let showAlert: @convention(block) (String) -> Void = { message inDispatchQueue.main.async {let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))self.present(alert, animated: true, completion: nil)}}jsContext.setObject(showAlert, forKeyedSubscript: "showAlert" as NSString)// 执行 JavaScript 代码let jsCode = """showAlert("Hello from JavaScript");"""jsContext.evaluateScript(jsCode)}
}

对比总结

特性WKScriptMessageJavaScriptCore
适用 WebViewWKWebViewUIWebView(已弃用)或不使用 WebView
消息传递通过消息传递直接调用
复杂度简单易用功能强大但复杂
性能较高取决于使用场景
安全性需要处理潜在的安全问题
使用场景适用于现代 WebView 交互适用于需要复杂 JavaScript 处理的场景

性能问题与监控

性能问题
  • WKScriptMessage:由于通过消息传递,性能通常较好,但频繁的大数据传输可能会导致性能问题。
  • JavaScriptCore:直接调用,性能较高,但复杂操作可能会影响性能。
性能监控
  1. 日志记录:在调用前后记录时间戳,计算耗时。
  2. 使用 Instruments:分析 CPU 使用率、内存占用和线程活动。
  3. 代码审查:定期分析和优化代码。

小结

WKScriptMessageJavaScriptCore 各有优缺点,选择哪种方式取决于具体的使用场景和需求。通过适当的监控和优化,可以确保 jsBridge 的高效运行。

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

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

相关文章

音频流格式启用数据流

音频流格式启用数据流 音频流格式启用数据流使用 AudioStreamBasicDescription 结构在哪里以及如何设置流格式 音频流格式启用数据流 在单个样本帧级别处理音频数据时&#xff0c;就像使用音频单元一样&#xff0c;仅仅指定正确的数据类型来表示音频是不够的。单个音频样本值中…

Vuetify3:Vuetify3 + Nuxt3时 tabs 跳转页面

在一开始没去看vuetify3的文档直接使用了nuxt3跳转方式 <template><v-tabs><NuxtLink :to"/yourRouter"><v-tab to"/tab1">Tab 1</v-tab></NuxtLink><v-tab to"/tab2"><NuxtLink :to"/yourR…

升级confluence中的内嵌tomcat

步骤&#xff1a; 1、下载新版本tomcat 下载地址&#xff1a;https://tomcat.apache.org/download-90.cgi 2、关闭confluence 进入confluence的bin目录&#xff0c;执行./stop-confluence.sh 3、备份confluence 在对应目录下&#xff0c;执行 cp ./confluence -r ./conflu…

HandlerMethodArgumentResolver :深入spring mvc参数解析机制

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; 搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到三十…

编程新纪元:AI辅助工具豆包Marscode体验

自从ChatGPT带动全球AI热潮&#xff0c;AI席卷着各行各业。编程界也不例外&#xff0c;早期做过了Github Copilot、阿里的通义灵码等AI编程插件的体验 p.s.以上的下载量与评分均只是plugins.jetbrains的marketplace数据&#xff0c;仅供参考 基本AI编程工具的功能都差不多&…

目标检测中的mAP计算:深入解析与实践指南

目标检测中的mAP计算&#xff1a;深入解析与实践指南 在目标检测任务中&#xff0c;评估模型性能是一个复杂的过程&#xff0c;因为需要同时考虑检测的准确性和召回率。平均精度均值&#xff08;mean Average Precision&#xff0c;简称mAP&#xff09;是一个广泛使用的评估指…

自然语言处理学习(3)RNN 模型学习---NLP领域的第一个模型

一 基本定义 视频链接 1.小案例理解–语义理解 目的&#xff1a;输入一句话&#xff0c;机器需要理解这句话的语义 二. RNN模型分类 1. 按照输入输出分类 (1) N Vs N (2) N Vs 1 (3) 1 VsN (4) seq2seq 三 传统RNN模型 1. 内部结构分析 &#xff08;a) 总体外…

基于单片机的多功能电子时钟的设计

摘要&#xff1a;提出了一种基于单片机的多功能电子时钟的设计方法&#xff0c;以 AT89C52单片机作为系统的主控芯片&#xff0c;采用DS1302作为时钟控制芯片&#xff0c;实现日期时钟显示并且提供精准定时的功能。此外&#xff0c;还可经由DHT22所构成的温湿度传感电路&#x…

Kafka集群部署(手把手部署图文详细版)

1.1.1 部署zookpeer 在node02下载并解压zookeeper软件包 cd /usr/local wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz 或者&#xff1a;scp cat192.168.28.100:/home/cat/zookeeper-3.4.6.tar.gz /tmp&#xff08;注意目录&#xf…

vue属性绑定v-bind

属性绑定v-bind 双大括号不能在HTML attributes 中使用。想要响应式地绑定一个attribute&#xff0c;应该使用v-bind指令。 v-bind 指令指示Vue将元素id attribute 与组件的dyid属性保持一致。如果绑定值是null或者undefined&#xff0c;那么该attribute将会从渲染的元素上移…

昇思第9天

LSTMCRF序列标注 序列标注&#xff1a;对序列进行标注&#xff0c;实际上是对序列中每个Token进行标签预测&#xff0c;可以直接视作简单的多分类问题。但是序列标注不仅仅需要对单个Token进行分类预测&#xff0c;同时相邻Token直接有关联关系&#xff0c;需要引入一种能够学…

docker介绍与详细安装

1 docker 介绍 1.1 虚拟化 在计算机中&#xff0c;虚拟化&#xff08;英语&#xff1a;Virtualization&#xff09;是一种资源管理技术&#xff0c;是将计算机的各种实体资源&#xff0c;如服务器、网络、内存及存储等&#xff0c;予以抽象、转换后呈现出来&#xff0c;打破实…

c++【入门】交换数值

限制 时间限制 : 1 秒 内存限制 : 128 MB 题目 我们现在要做一个非常简单的题目&#xff0c;实现一个完整的程序。 当它运行起来后&#xff0c;我们希望通过键盘输入两个整数&#xff0c;我们先把它们称为 a 和 b。然后把他们之间的值进行交换并输出。 输入 输入两个数字…

【BUUCTF-PWN】12-get_started_3dsctf_2016

32位&#xff0c;开启了NX保护 执行效果&#xff1a; main函数&#xff1a; 其中gets()函数存在栈溢出&#xff0c;溢出距离为0x38&#xff0c;这里是使用的esp寻址&#xff0c;属于外平栈&#xff0c;不需要覆盖ebp的四个字节。而之前做的题一般都是ebp寻址&#xff0c;…

开发国际短剧系统的策略解析

一、明确项目目标和需求 1、功能需求&#xff1a;确定系统应具备的基本功能&#xff0c;如用户注册、登录、浏览短剧、评论、分享、个性化推荐等。 2、性能需求&#xff1a;确保系统能够承受高并发访问&#xff0c;保证视频流畅播放&#xff0c;减少卡顿和延迟。 3、跨文化传播…

MCU中如何利用串口通信,增加AT指令框架

第一步&#xff0c;通过串口与PC端建立通信第二步&#xff0c;根据PC端发来的AT指令&#xff0c;MCU执行相应代码 主要是解析PC端发来的字符串&#xff0c;也就是获取字符串、处理字符串、以及分析字符串。 1. 串口通信 用到的是DMA串口通信&#xff0c;收发字符串数据时&…

Linux中的LVM逻辑卷管理:创建、扩展和缩减逻辑卷

Linux中的LVM逻辑卷管理&#xff1a;创建、扩展和缩减逻辑卷 引言 逻辑卷管理&#xff08;LVM&#xff09;是Linux系统中一种高级的硬盘管理技术&#xff0c;它提供了灵活的磁盘空间管理方式。通过LVM&#xff0c;您可以更灵活地创建、扩展和缩减逻辑卷&#xff0c;以满足不断…

Vbus 和 Vbat

在嵌入式系统开发中&#xff0c;Vbus 和 Vbat 是两个不同的电源相关术语&#xff0c;它们的区别主要在于它们的用途和连接的电源类型。 Vbus 定义: Vbus 通常是指 USB 总线电压。在 USB 2.0 中&#xff0c;Vbus 通常为 5V 电源。用途: Vbus 提供电源给 USB 设备&#xff0c;确…

如何使用 3D 建模库在 C# 中将 3DS 转换为 USDZ?

USDZ/USD是一种 3D 文件格式&#xff0c;被广泛用于跨平台共享 3D 资产。另一方面&#xff0c;3DS是另一种以块形式存储数据的 3D 文件格式。在某些情况下&#xff0c;您需要将3DS 文件转换为 USDZ/USD文件格式。因此&#xff0c;本篇博文介绍了一个功能丰富的3D 建模库&#x…

【基于R语言群体遗传学】-6-表型计算等位基因频率、最大似然估计方法

到目前为止&#xff0c;我们主要讨论了等位基因和基因型频率&#xff0c;以及我们如何可以从一个推断出另一个。但是&#xff0c;如果我们不知道等位基因频率&#xff0c;只知道种群中存在哪些表型呢&#xff1f;如果我们足够幸运&#xff0c;知道哪些表型对应哪些基因型&#…