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

android,flutter 混合开发,pigeon通信,传参

文章目录

        • app效果
        • native和flutter通信的基础知识
          • 1. 编解码器 一致性和完整性,安全性,性能优化
          • 2. android代码
          • 3. dart代码
        • 1. 创建flutter_module
        • 2.修改 Android 项目的 settings.gradle,添加 Flutter module
        • 3. 在 Android app 的 build.gradle 中添加依赖
        • 4. 原生和flutter_module通信BasePlugin
        • 5. io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister 自动注册插件
        • 6 手动注册
        • 7. 通信关闭flutter页面
        • 8. dartEntrypointArgs传入参数
        • 9. 通信传入参数
          • 9.1 发送参数
          • 9.1 接收参数
        • 10. android代码
        • 11 源码

app效果
在这里插入图片描述
native和flutter通信的基础知识

低级的消息通道,一般不直接使用
ServicesBinding.instance.defaultBinaryMessenger
高级别的消息通道,对defaultBinaryMessenger进行了封装,提供的更简单的api发送和接收消息
BasicMessageChannel MethodChannel EventChannel
MethodChannel EventChannel底层都是基于BasicMessageChannel

1. 编解码器 一致性和完整性,安全性,性能优化

MethodChannel,EventChannel->StandardMethodCodec
BasicMessageChannel->StandardMessageCodec
StandardMessageCodec:支持基本的数据类型(字符串、数字、布尔值、字节数组、列表、映射等)。
StandardMethodCodec:除了支持基本的数据类型外,还支持方法调用的参数和返回结果的编码和解码。
StringCodec:由于只处理字符串,StringCodec 的实现更为简单,性能更高

2. android代码
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {basicMessageChannel = BasicMessageChannel(flutterEngine.dartExecutor.binaryMessenger, BASIC_CHANNEL, StringCodec.INSTANCE)//创建MethodChannelmethodChannel =MethodChannel(flutterEngine.dartExecutor, BASIC_CHANNEL, StandardMethodCodec.INSTANCE)//创建EventChanneleventChannel = EventChannel(flutterEngine.dartExecutor, BASIC_CHANNEL)basicMessageChannel.send("dddd")basicMessageChannel.setMessageHandler { message, reply ->reply.reply("dddd")Log.e("dddd", message.toString())}methodChannel.invokeMethod("getPlatformVersion", null)methodChannel.setMethodCallHandler { call, result ->when (call.method) {"getPlatformVersion" -> {result.success("Android ${android.os.Build.VERSION.RELEASE}")}else -> {result.notImplemented()}}}eventChannel.setStreamHandler(object : EventChannel.StreamHandler {override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {eventSink = eventseventSink?.success("Event")}override fun onCancel(arguments: Any?) {eventSink = null}})}
3. dart代码
class _StudyChannelState extends State<StudyChannel> {MethodChannel methodChannel = const MethodChannel('base_plugin');EventChannel eventChannel = const EventChannel('base_plugin');static const basicMessageChannel = BasicMessageChannel<String>('base_plugin', StringCodec());  void initState() {super.initState();//只接收eventChannel.receiveBroadcastStream().listen((value){});//监听methodChannel.setMethodCallHandler((call){call.method == "getData" ? print("getData") : print("method=$call");return Future.value("methodChannel=$call");});//执行,相当于发送methodChannel.invokeListMethod("getData");//发送basicMessageChannel.send("data");//监听basicMessageChannel.setMessageHandler((message){return Future.value("basicMessageChannel=$message");});}Widget build(BuildContext context) {return const Placeholder();}
}
1. 创建flutter_module

File->New->New Flutter Project
name为flutter_module
选择project type为module

2.修改 Android 项目的 settings.gradle,添加 Flutter module
pluginManagement {repositories {google {content {includeGroupByRegex("com\\.android.*")includeGroupByRegex("com\\.google.*")includeGroupByRegex("androidx.*")}}mavenCentral()gradlePluginPortal()}
}
dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)repositories {google()mavenCentral()maven(url = "https://storage.googleapis.com/download.flutter.io")}
}rootProject.name = "hunheandroid"
include(":app")
//主要是这一句
apply(from = "../flutter_module/.android/include_flutter.groovy")
3. 在 Android app 的 build.gradle 中添加依赖
dependencies {implementation(project(":flutter"))
}
4. 原生和flutter_module通信BasePlugin

参考文章生成对应的io/flutter/plugins/Messages.g.kt
用pigeon kotlin swift写一个自己的插件
拷贝BasePlugin

package io.flutter.pluginsimport android.app.Activity
import android.util.Log
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding/** BasePlugin */
/** BasePlugin */
class BasePlugin : FlutterPlugin, HostMessageApi, ActivityAware {companion object {private var flutterMessageApi: FlutterMessageApi? = nullfun getFlutterMessageApi(): FlutterMessageApi? {return flutterMessageApi}}private var activity: Activity? = nullprivate var tag = "BasePlugin"override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {Log.e(tag, "onAttachedToEngine-start")HostMessageApi.setUp(flutterPluginBinding.binaryMessenger, this)flutterMessageApi = FlutterMessageApi(flutterPluginBinding.binaryMessenger)Log.e(tag, "onAttachedToEngine-end")}override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {HostMessageApi.setUp(binding.binaryMessenger, null)}override fun flutter2Native(message: String, type: Long): String {print("flutter2Native=message=start=>$message=type=$type")return "flutter2Native=message=$message=type=$type"}override fun flutter2NativeAsync(message: String,type: Long,callback: (Result<String>) -> Unit) {print("flutter2NativeAsync=message=$message=type=$type")callback(Result.success("flutter2NativeAsync=message=$message=type=$type"))if (type == 1L) {closeCurrentActivity()}}private fun closeCurrentActivity() {activity?.finish()}override fun onAttachedToActivity(binding: ActivityPluginBinding) {this.activity = binding.activity}override fun onDetachedFromActivityForConfigChanges() {}override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}override fun onDetachedFromActivity() {this.activity = null}
}
5. io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister 自动注册插件
 public static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine) {try {Class<?> generatedPluginRegistrant =Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");Method registrationMethod =generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);registrationMethod.invoke(null, flutterEngine);} catch (Exception e) {Log.e(TAG,"Tried to automatically register plugins with FlutterEngine ("+ flutterEngine+ ") but could not find or invoke the GeneratedPluginRegistrant.");Log.e(TAG, "Received exception while registering", e);}}
package io.flutter.plugins;import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;import io.flutter.embedding.engine.FlutterEngine;/*** Generated file. Do not edit.* This file is generated by the Flutter tool based on the* plugins that support the Android platform.*/
@Keep
public final class GeneratedPluginRegistrant {private static final String TAG = "GeneratedPluginRegistrant";public static void registerWith(@NonNull FlutterEngine flutterEngine) {try {Log.e(TAG, "registerWith-start");flutterEngine.getPlugins().add(new BasePlugin());Log.e(TAG, "registerWith-end");} catch (Exception e) {Log.e(TAG, "Error registering plugin base_plugin, com.app.base_plugin.BasePlugin", e);}}
}
6 手动注册

flutterEngine.getPlugins().add(new BasePlugin());

7. 通信关闭flutter页面

使用flutter和原生通信,在收到消息以后,关闭当前页面
BasePlugin实现ActivityAware,获取到activity
在收到flutter传入进来的消息的时候关闭activity

8. dartEntrypointArgs传入参数
//跳转带入参数
val initialRoute = listOf(  "aaa","bbbb")startActivity(withNewEngine().dartEntrypointArgs(initialRoute)  .build(this))
//args就是传入的参数
void main(List<String> args){print("args=$args");runApp(const MyApp());
}
9. 通信传入参数
9.1 发送参数
 val initialRoute = listOf(  "/page2","bbbb")BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1){Log.e(tag, "flutter2NativeAsync: $it")FlutterLibrary.startFlutterPage(this)}
9.1 接收参数

class RouterPage extends StatefulWidget {const RouterPage({super.key});State<RouterPage> createState() => _RouterPageState();
}class _RouterPageState extends State<RouterPage> implements FlutterMessageApi {late String args;void initState() {super.initState();FlutterMessageApi.setUp(this);}String native2Flutter(String message, int type) {print("native2Flutter=$message $type");setState(() {args = message;});return "我是原生调用flutter方法返回的值=》native2Flutter";}Future<String> native2FlutterAsync(String message, int type) {args = message;print("native2Flutter=$message $type");return Future.value("我是原生调用flutter方法返回的值=》native2FlutterAsync");}Widget build(BuildContext context) {// final value = widget.args.isNotEmpty ? widget.args[0] : "/";if (args.isEmpty||!args.contains("#")) {return MyHomePage(title: "首页");}final value = args.split("#").first;switch (value) {case '/page2':return SecondPage();}print("_RouterPageState=build");return MyHomePage(title: "首页");}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;State<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage>  {int _counter = 0;void _incrementCounter() {setState(() {_counter++;});}void initState() {super.initState();}Widget build(BuildContext context) {print("_MyHomePageState=build");return Scaffold(appBar: AppBar(title: Text(widget.title), leading: BackButton()),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[TextButton(onPressed: () {BasePlugin.flutter2NativeAsync("flutter2NativeAsync", 1).then((value,) {print("flutter2NativeAsync=$value");});},child: Text('flutter2NativeAsync'),),TextButton(onPressed: () {Navigator.of(context).pushNamed("/page2");},child: Text('flutter2NativeAsync'),),const Text('You have pushed the button this many times:'),Text('$_counter',style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),), // This trailing comma makes auto-formatting nicer for build methods.);}}class SecondPage extends StatelessWidget {const SecondPage({super.key});Widget build(BuildContext context) {print("SecondPage=build");return Scaffold(appBar: AppBar(title: Text("SecondPage")),body: Center(child: TextButton(onPressed: () {Navigator.of(context).pop();},child: Text('关闭'),),),);}
}
10. android代码
package com.example.hunheandroidimport android.app.Application
import android.content.Context
import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.FlutterEngineGroup
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.plugins.BasePluginconst val ENGINE_ID = "my_engine_id"
object FlutterLibrary {fun init(application: Application) {FlutterEngineManager.getInstance().init(application)}fun startFlutterPage(context: Context) {val intent = FlutterActivity.withCachedEngine(ENGINE_ID).build(context).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)context.startActivity(intent)}
}// FlutterEngineManager.kt
class FlutterEngineManager private constructor() {private lateinit var engineGroup: FlutterEngineGroupprivate var engine: FlutterEngine? = nullcompanion object {private var instance: FlutterEngineManager? = nullfun getInstance(): FlutterEngineManager {return instance ?: synchronized(this) {instance ?: FlutterEngineManager().also { instance = it }}}}fun init(application: Application) {engineGroup = FlutterEngineGroup(application)engine = engineGroup.createAndRunEngine(application,DartExecutor.DartEntrypoint.createDefault())FlutterEngineCache.getInstance().put(ENGINE_ID, engine)engine!!.plugins.add(BasePlugin())}fun getEngine(): FlutterEngine? {return engine}fun destroyEngine() {engine?.destroy()engine = null}
}class GoFlutterActivity : FlutterActivity(), HostMessageApi {private val tag = "GoFlutterActivity"private lateinit var binding: ActivityGoFlutterBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityGoFlutterBinding.inflate(layoutInflater)setContentView(binding.root)binding.goFlutter.setOnClickListener {//跳转到flutterval initialRoute = listOf(  // Map 形式的参数"/","aaaa")BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1) {Log.e(tag, "flutter2NativeAsync: $it")FlutterLibrary.startFlutterPage(this)}}binding.goFlutter2.setOnClickListener {//跳转到flutterval initialRoute = listOf(  // Map 形式的参数"/page2","bbbb")BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1) {Log.e(tag, "flutter2NativeAsync: $it")FlutterLibrary.startFlutterPage(this)}}}override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {Log.e(tag, "configureFlutterEngine")
//        GeneratedPluginRegistrant.registerWith(flutterEngine)}override fun flutter2Native(message: String, type: Long): String {Log.e(tag, "$message$type")return "我是flutter调用原生方法的返回值=》flutter2Native"}override fun flutter2NativeAsync(message: String,type: Long,callback: (Result<String>) -> Unit) {Log.e(tag, "$message$type")callback(Result.success("我是flutter调用原生方法的返回值=》flutter2NativeAsync"))}}
11 源码

gitee

相关文章:

android,flutter 混合开发,pigeon通信,传参

文章目录 app效果native和flutter通信的基础知识1. 编解码器 一致性和完整性&#xff0c;安全性&#xff0c;性能优化2. android代码3. dart代码 1. 创建flutter_module2.修改 Android 项目的 settings.gradle&#xff0c;添加 Flutter module3. 在 Android app 的 build.gradl…...

at32f403a rt thread led基础bsp工程测试

1.led工程官方bsp使用 导出一个独立的AT32F403A的BSP工程 下载RTT源代码 gitee更新较慢 https://gitee.com/rtthread/rt-thread github版本更新最新 https://github.com/RT-Thread/rt-thread. 切换到V5.1.0分支(使用一个发布版本可以避免不必要的bug) 导出一个独立的AT32BSP…...

DeepSeek写贪吃蛇手机小游戏

DeepSeek写贪吃蛇手机小游戏 提问 根据提的要求&#xff0c;让DeepSeek整理的需求&#xff0c;进行提问&#xff0c;内容如下&#xff1a; 请生成一个包含以下功能的可运行移动端贪吃蛇H5文件&#xff1a; 要求 蛇和食物红点要清晰&#xff0c;不超过屏幕外 下方有暂停和重新…...

【好玩的工具和命令】 ASCII 艺术生成工具: figlet

figlet 是一款用于生成 ASCII 艺术文字的工具&#xff0c;支持多种字体样式。它能将输入的文本转换为由字符组成的大型字母图案&#xff0c;广泛应用于命令行环境下的标题展示或装饰。 核心功能 生成 ASCII 文字艺术&#xff1a;将普通文本转化为大号的、由字符构成的艺术字…...

工具--安川伺服故障代码

上传一下安川伺服故障代码&#xff0c;后续结合实际维修经验&#xff0c;逐个整理分析&#xff0c;绝对超出手册经验 故障代码 故障描述 a.020/a.02 用户参数和数检查异常 1 a.021/a.02 参数格式化异常 1 a.022/a.02 系统参数和数检查异常 1 a.023/a.02 参数密码异常…...

车载软件架构 --- OEM主机厂如何打入软件供应商内部?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...

AI 编程助手 cursor的系统提示词 prompt

# Role 你是一名极其优秀具有10年经验的产品经理和精通java编程语言的架构师。与你交流的用户是不懂代码的初中生&#xff0c;不善于表达产品和代码需求。你的工作对用户来说非常重要&#xff0c;完成后将获得10000美元奖励。 # Goal 你的目标是帮助用户以他容易理解的…...

Matlab写入点云数据到Rosbag

最近有需要读取一个点云并做处理后&#xff0c;重新写回rosbag。网上有很多读取的教程&#xff0c;但没有写入。自己写入时也遇到了很多麻烦&#xff0c;踩了一堆坑进行记录。 1. rosbag中一个lidar的msg有哪些信息&#xff1f; 通过如下代码&#xff0c;先读取一个rosbag的l…...

业务流程相关的权威认证和培训有哪些

业务流程的认证和培训种类繁多&#xff0c;旨在帮助专业人士掌握业务流程管理 (BPM) 的知识和技能&#xff0c;从而提升个人职业发展和组织运营效率。下面分别介绍&#xff1a; 一、 业务流程认证和培训的种类 业务流程的认证和培训可以大致分为以下几类&#xff0c;涵盖了不…...

基于Spring Boot的兴顺物流管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

【算法系列】荷兰国旗问题:三指针法原地排序

一、题目(leetcode75 颜色分类 --三分数组) 二、思路 算法核心&#xff1a;三指针分治策略 该问题被称为“荷兰国旗问题”&#xff08;Dutch National Flag Problem&#xff09;&#xff0c;由计算机科学家Edsger Dijkstra提出。其核心思想是通过三个指针将数组划分为三个区…...

DeepSeek R1本地+私有云版医疗AI部署开发成功案例技术剖析

1. 引言 1.1 研究背景与意义 随着科技的飞速发展,人工智能(AI)在医疗领域的应用正逐渐成为推动医疗行业变革的重要力量。近年来,医疗 AI 取得了显著的进展,从疾病诊断、药物研发到医疗管理等各个环节,AI 技术都展现出了巨大的潜力。它能够处理和分析海量的医疗数据,为…...

ARM64 Trust Firmware [五]

本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC&#xff0c;必须从 SMC 指令本身开始&#xff0c;其指令如下图&#xff1a; 指令格式为&#xff1a;SMC #<imm>&#xff0c;从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用&#xff…...

rkipc main.c 中 rk_param_init函数分析

rk_param_init函数 这个函数是用来读取配置文件进行参数配置 这个函数在 luckfox-pico/project/app/rk_smart_door/smart_door/common/uvc/param/param.c 中 这个函数在main函数中被调用 //通过-c 配置文件路径 把配置文件传进来 case c:rkipc_ini_path_ optarg;//调用&am…...

正确清理C盘空间

一.系统清理 正确清理C盘空间主要是删除不需要的文件和应用程序&#xff0c;以释放磁盘空间。以下是一些常用的方法&#xff1a; 删除临时文件&#xff1a;在Windows搜索框中输入“%temp%”&#xff0c;打开临时文件夹&#xff0c;将其中的文件全部删除。 清理回收站&#xf…...

http代理IP怎么实现?如何解决代理IP访问不了问题?

HTTP代理是一种网络服务&#xff0c;它充当客户端和目标服务器之间的中介。当客户端发送请求时&#xff0c;请求首先发送到代理服务器&#xff0c;然后由代理服务器转发到目标服务器。同样&#xff0c;目标服务器的响应也会先发送到代理服务器&#xff0c;再由代理服务器返回给…...

【Gin-Web】Bluebell社区项目梳理5:投票功能分析与实现

本文目录 一、投票功能投票流程实现代码redis投票 一、投票功能 投票流程 首先我们要明确&#xff0c;就是 谁&#xff08;哪个用户&#xff1a;userID&#xff09; 给 哪个帖子&#xff08;postID&#xff09; 投了 什么票&#xff08;赞成票or反对票&#xff09;。 赞成票…...

多人协同创作gitea

多人协同创作gitea 在多台设备上协同使用Gitea&#xff0c;主要是通过网络访问Gitea服务器上的仓库来进行代码管理和协作。以下是一些关键步骤和建议&#xff0c;帮助你在多台设备上高效地使用Gitea进行协作&#xff1a; 1. 确保Gitea服务可访问 首先&#xff0c;你需要确保…...

Java 大视界 -- Java 大数据未来十年的技术蓝图与发展愿景(95)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

idea连接gitee完整教程

文章目录 idea连接gitee(使用idea远程兼容gitee) 使用idea远程兼容gitee并反向创建仓库和分支...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...