RK3568 RTC驱动实验

RK3568 RTC驱动实验

1. RTC简介

​ RTC 也就是实时时钟,用于记录当前系统时间,对于 Linux 系统而言时间是非常重要的,使用 Linux 设备的时候也需要查看时间。RTC是Linux的时间系统。

​ RTC 设备驱动是一个标准的字符设备驱动,应用程序通过 open、 release、 read、 write 和 ioctl 等函数完成对 RTC 设备的操作。

2. RTC相关结构体

// Linux内核将 RTC 设备抽象为 rtc_device 结构体
struct rtc_device {
    struct device dev;                 // 设备
    struct module *owner;

    int id;                            // ID

    const struct rtc_class_ops *ops;   // RTC 设备底层操作函数
    struct mutex ops_lock;

    struct cdev char_dev;             // 字符设备
    unsigned long flags;

    unsigned long irq_data;
    spinlock_t irq_lock;
    wait_queue_head_t irq_queue;
    struct fasync_struct *async_queue;

    int irq_freq;
    int max_user_freq;

    struct timerqueue_head timerqueue;
    struct rtc_timer aie_timer;
    struct rtc_timer uie_rtctimer;
    struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
    int pie_enabled;
    struct work_struct irqwork;
    /* Some hardware can't support UIE mode */
    int uie_unsupported;

    /* Number of nsec it takes to set the RTC clock. This influences when
     * the set ops are called. An offset:
     *   - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s
     *   - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s
     *   - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s
     */
    long set_offset_nsec;

    bool registered;

    struct nvmem_device *nvmem;
    /* Old ABI support */
    bool nvram_old_abi;
    struct bin_attribute *nvram;

    time64_t range_min;
    timeu64_t range_max;
    time64_t start_secs;
    time64_t offset_secs;
    bool set_start_time;

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
    struct work_struct uie_task;
    struct timer_list uie_timer;
    /* Those fields are protected by rtc->irq_lock */
    unsigned int oldsecs;
    unsigned int uie_irq_active:1;
    unsigned int stop_uie_polling:1;
    unsigned int uie_task_active:1;
    unsigned int uie_timer_active:1;
#endif
};

// RTC 设备的最底层操作函数集合,用户编写
// 只是最底层的 RTC 设备操作函数,并不是提供给应用层的file_operations 函数操作集。
struct rtc_class_ops {
    int (*ioctl)(struct device *, unsigned int, unsigned long);
    int (*read_time)(struct device *, struct rtc_time *);
    int (*set_time)(struct device *, struct rtc_time *);
    int (*read_alarm)(struct device *, struct rtc_wkalrm *);
    int (*set_alarm)(struct device *, struct rtc_wkalrm *);
    int (*proc)(struct device *, struct seq_file *);
    int (*set_mmss64)(struct device *, time64_t secs);
    int (*set_mmss)(struct device *, unsigned long secs);
    int (*read_callback)(struct device *, int data);
    int (*alarm_irq_enable)(struct device *, unsigned int enabled);
    int (*read_offset)(struct device *, long *offset);
    int (*set_offset)(struct device *, long offset);
};

// 提供给应用层的file_operations 函数操作集 drivers/rtc/rtc-dev.c 
static const struct file_operations rtc_dev_fops = {
    .owner      = THIS_MODULE,
    .llseek     = no_llseek,
    .read       = rtc_dev_read,
    .poll       = rtc_dev_poll,
    .unlocked_ioctl = rtc_dev_ioctl,
    .open       = rtc_dev_open,
    .release    = rtc_dev_release,
    .fasync     = rtc_dev_fasync,
};  

3. RTC整体调用框架

在这里插入图片描述

4. RTC代码解析

涉及到的目录功能总结
class.c:向linux设备模型核心注册了一个类RTC,提供了RTC子系统的一些公共函数,让各个RTC驱动注册集成到我们的linux内核中,向驱动程序提供了注册/注销接口。
rtc-dev.c:定义了基本的设备文件操作函数,用户程序与RTC驱动的接口函数,这里定义了每个ioctl命令需要调用的函数,还有open,read等。
interface.c:提供了ioctl各个命令需要调用的函数。
rtc-sysfs.c:与sysfs有关,提供通过sys文件系统操作pcf8563。
rtc-proc.c:与proc文件系统有关,提供通过proc文件系统操作pcf8563。
hctosys.c:系统起来之后会调用到这个文件中的rtc_hctosys()函数,主要功能是系统起来的时候去读RTC硬件中的时间,然后更新我们的系统时间。
rtc.h:定义了与RTC有关的数据结构。

5. RTC驱动注册函数解析

// 驱动路径:drivers/rtc/class.c
struct class *rtc_class;
rtc_init
    -> rtc_class = class_create(THIS_MODULE, "rtc");      // 创建名为rtc的class
    -> rtc_class->pm = RTC_CLASS_DEV_PM_OPS;              // 提供休眠唤醒相关接口suspend/resume
    -> rtc_dev_init();                                    // 动态申请/dev/rtcN的设备号
    	-> alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");    // RTC_DEV_MAX=16
subsys_initcall(rtc_init);                                // rtc_sysfs_init():rtc类具有的device_attribute属性

rtc_device_register
    -> id = rtc_device_get_id(dev);           // Linux支持多个RTC设备,所以需要为每一个设备分配一个ID
    	-> ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);     // 对应与/dev/rtc0  /dev/rtc1  /dev/rtcN
     -> rtc = rtc_allocate_device();
     	-> struct rtc_device *rtc;
     	-> rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);         // 创建rtc_device设备(对象)并初始化
      	-> ...... rtc->dev.class = rtc_class;  ......       // rtc_init创建的rtc_class
    	// rtc设备中相关锁,等待队列的初始化
     	-> mutex_init(&rtc->ops_lock);
    	-> spin_lock_init(&rtc->irq_lock);
    	-> init_waitqueue_head(&rtc->irq_queue);
     	// 初始化工作队列rtc_timer_do_work
     	-> timerqueue_init_head(&rtc->timerqueue);
    	-> INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
     	// 初始化rtc闹钟中断
    	-> rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);
     	// RTC更新中断
     	-> rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);
      	// RTC周期性中断
      	-> hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    	-> rtc->pie_timer.function = rtc_pie_update_irq;
    	-> rtc->pie_enabled = 0;
    -> rtc->id = id;
    -> rtc->ops = ops;            // 对应RTC驱动填充的底层操作函数
    -> rtc->owner = owner;
    -> rtc->dev.parent = dev;
    -> dev_set_name(&rtc->dev, "rtc%d", id);   // 设置rtc的dev成员中的name域
    -> __rtc_read_alarm(rtc, &alrm);        // 检查是否设置闹钟
    -> if (!err && !rtc_valid_tm(&alrm.time))    // 如果RTC芯片中设置有效的Alarm,则初始化,加入队列中
        rtc_initialize_alarm(rtc, &alrm);
    -> rtc_dev_prepare(rtc);               // /dev/rtc0的rtc作为字符设备进行初始化
    	-> cdev_init(&rtc->char_dev, &rtc_dev_fops);     // rtc_dev_fops接口操作函数结构体
     		-> cdev->ops = fops;
    -> cdev_device_add(&rtc->char_dev, &rtc->dev);
    	-> cdev_add(cdev, dev->devt, 1);   // rtc设备作为字符设备添加到系统    生成/dev/rtc0
     -> rtc_proc_add_device(rtc);        // /proc/rtc
     	-> proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, rtc);
      
// 提供给用户层的接口
static const struct file_operations rtc_dev_fops = {
    .owner      = THIS_MODULE,
    .llseek     = no_llseek,
    .read       = rtc_dev_read,
    .poll       = rtc_dev_poll,
    .unlocked_ioctl = rtc_dev_ioctl,
    .open       = rtc_dev_open,
    .release    = rtc_dev_release,
    .fasync     = rtc_dev_fasync,
};

kernel中__init类型函数都位于.init.text段中,对应的在.initcall.init段中保存相应的函数指针。系统在启动过程中,根据定义在段中的等级值(0~7)从低到高依次执行。定义:

// include/linux/init.h
#define pure_initcall(fn)       __define_initcall(fn, 0)
#define core_initcall(fn)       __define_initcall(fn, 1)
#define core_initcall_sync(fn)      __define_initcall(fn, 1s)
#define postcore_initcall(fn)       __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)
#define arch_initcall(fn)       __define_initcall(fn, 3)
#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)
#define subsys_initcall(fn)     __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)
#define fs_initcall(fn)         __define_initcall(fn, 5)
#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)
#define rootfs_initcall(fn)     __define_initcall(fn, rootfs)
#define device_initcall(fn)     __define_initcall(fn, 6)
#define device_initcall_sync(fn)    __define_initcall(fn, 6s)
#define late_initcall(fn)       __define_initcall(fn, 7)
#define late_initcall_sync(fn)      __define_initcall(fn, 7s)

6. 应用层调用驱动流程解析

rtc_dev_ioctl (struct file *file, unsigned int cmd, unsigned long arg)           // drivers/rtc/rtc-dev.c   
    -> struct rtc_device *rtc = file->private_data;               // 获取到rtc设备
    -> switch (cmd) 
    -> case RTC_RD_TIME:
    -> rtc_read_time     // drivers/rtc/interface.c
        -> __rtc_read_time
            -> rtc->ops->read_time(rtc->dev.parent, tm);
    -> case RTC_SET_TIME:
    -> rtc_set_time      // drivers/rtc/interface.c
    	-> rtc_valid_tm(tm);       // 参数检查
     // 调用rtc_device中ops结构体的函数指针
     // ops结构体的函数指针已经在RTC驱动中被赋值
    -> if (!rtc->ops)
            err = -ENODEV;
        else if (rtc->ops->set_time)
            err = rtc->ops->set_time(rtc->dev.parent, tm);
        else if (rtc->ops->set_mmss64) {
            time64_t secs64 = rtc_tm_to_time64(tm);
            err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);

7. RTC时间查看与设置

RK809 内部 RTC 的使能需要先使能 RK809,默认已经使能,我们打开设备树 rk3568-evb.dtsi:

    rk809: pmic@20 {
        compatible = "rockchip,rk809";
        reg = <0x20>;
        interrupt-parent = <&gpio0>;
        interrupts = <3 IRQ_TYPE_LEVEL_LOW>;

        pinctrl-names = "default", "pmic-sleep",
                "pmic-power-off", "pmic-reset";
        pinctrl-0 = <&pmic_int>;
        pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>;
        pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>;
        pinctrl-3 = <&soc_slppin_gpio>, <&rk817_slppin_rst>;

        rockchip,system-power-controller;
        wakeup-source;
        #clock-cells = <1>;
        clock-output-names = "rk808-clkout1", "rk808-clkout2";
        //fb-inner-reg-idxs = <2>;
        /* 1: rst regs (default in codes), 0: rst the pmic */
        pmic-reset-func = <0>;
        /* not save the PMIC_POWER_EN register in uboot */
        not-save-power-en = <1>;

        vcc1-supply = <&vcc3v3_sys>;
        vcc2-supply = <&vcc3v3_sys>;
        vcc3-supply = <&vcc3v3_sys>;
        vcc4-supply = <&vcc3v3_sys>;
        vcc5-supply = <&vcc3v3_sys>;
        vcc6-supply = <&vcc3v3_sys>;
        vcc7-supply = <&vcc3v3_sys>;
        vcc8-supply = <&vcc3v3_sys>;
        vcc9-supply = <&vcc3v3_sys>;

​ 上面 status 状态没写,默认就是“okay”的。
​ 同时我们需要在 menuconfg 里对应的宏配置为 CONFIG RTC DRV RK808。> Device
Drivers > Real Time Clock 选中 CONFIG RTC DRV RK808。如下图。

在这里插入图片描述

8. 查看时间

如果要查看时间的话输入“date”命令即可,结果如图:

在这里插入图片描述
从上面可看到内核启动 RTC 时间采用的是 UTC 标准,而系统启动后采用的是 CST 标准
时间恰好相差8个小时。UTC(协调世界时)和CST(中部标准时间)是两个不同的时间标准,
在中国,CST 通常被解释为"China Standard Time"(中国标准时间),而不是"Central Standard Time
(中部标准时间)。中国 CST 与协调世界时(UTC)相差8小时,即 UTC+8。
RTC 时间设置也是使用的 date 命令,输入“date --help”命令即可査看 date 命令如何设置
系统时间,结果如图所示:

root@RK356X:/# date --help
Usage: date [OPTION]... [+FORMAT]
  or:  date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
Display the current time in the given FORMAT, or set the system date.

Mandatory arguments to long options are mandatory for short options too.
  -d, --date=STRING          display time described by STRING, not 'now'
      --debug                annotate the parsed date,
                              and warn about questionable usage to stderr
  -f, --file=DATEFILE        like --date; once for each line of DATEFILE
  -I[FMT], --iso-8601[=FMT]  output date/time in ISO 8601 format.
                               FMT='date' for date only (the default),
                               'hours', 'minutes', 'seconds', or 'ns'
                               for date and time to the indicated precision.
                      14T02:34:56-06:00
  -R, --rfc-email            output date and      Example: Mon, 14 Aug 2006 02:34:56 -0600
      --rfc-3339=              FMT='date', 'seconds', or 'ns'
                                        Example: 2006-08-14 02:34:56-06:00
  -r, -s, --set=STRING           set time described by STRING
  -u, -     --help     display this help and exit
      --version  outrpreted sequences are:

  %%   a literal %
  %a   locale's ab(e.g., Sunday)
  %b   locale's abbreviated month name (e.g., Ja date and time (e.g., Thu Mar  3 23:05:25 2005)
  %C   century;(e.g., 01)
  %D   date; same as %m/%d/%y
  %e   day of month, last two digits of year of ISO week number (see %G)
  %G   yearme as %b
  %H   hour (00..23)
  %I   hour (01..12)
  %j   day
            %l   hour, space padded ( 1..12); same as %_I
  %m   month ((000000000..999999999)
  %p   locale's equivalent of either AM rter of year (1..4)
  %r   locale's 12-hour clock time (e.g., 1conds since 1970-01-01 00:00:00 UTC
  %S   second (00..60)
  % is Monday
  %U   week number of year, with Sunday as first dayf week (01..53)
  %w   day of week (0..6); 0 is Sunday
  %W     locale's date representation (e.g., 12/31/99)
  %X   locale's(00..99)
  %Y   year
  %z   +hhmm numeric time zone (e.g., -04s numeric time zone (e.g., -04:00:00)
  %:::z  numeric time zon time zone abbreviation (e.g., EDT)

By default, date pads num:

  -  (hyphen) do not pad the field
  _  (underscore) pad wle
  #  use opposite case if possible

After any flags comes er, which is either
E to use the locale's alternate representats if available.

Examples:
Convert seconds since the epoch (1ime on the west coast of the US (use tzselect(1) to find TZ)
  iday on the west coast of the US
  $ date --date='TZ="America/Lww.gnu.org/software/coreutils/>
Report date translation bugs to://www.gnu.org/software/coreutils/date>

比如现在设置当前时间为2024年4月1日11:40:00,因此输入如下:

date -s "2024-04-01 11:40:00"

在这里插入图片描述

设置完成后再次使用date命令查看一下当前时间就会发现时间改过来了

大家注意我们使用date -s命令仅仅是修改了当前时间,此时间还没有写入到RK809内部 RTC 里面或其他的 RTC 芯片里面,因此系统重启以后时间又会丢失。我们需要将当前的时间写入到 RTC 里面,这里要用到hwclock命令,输入如下命令将系统时间写入到 RTC 里面:

hwclock -w     /将当前系统时间写入RTC里面/

时间写入到 RTC 里面以后就不怕系统重启以后时间丢失了

间隔时间输入如下命令:

hwclock -r    /读取当前系统时间/

在这里插入图片描述

发现当前系统时间在走动,系统时间正常。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

强大缓存清理工具 NetShred X for Mac激活版

NetShred X for Mac是一款专为Mac用户设计的强大缓存清理工具&#xff0c;旨在帮助用户轻松管理和优化系统性能。这款软件拥有直观易用的界面&#xff0c;即使是初次使用的用户也能快速上手。 软件下载&#xff1a;NetShred X for Mac激活版下载 NetShred X能够深入扫描Mac系统…

【MATLAB】PSO_BP神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 PSO_BP神经网络时序预测算法是一种结合了粒子群优化(PSO)算法和反向传播(BP)神经网络的时序预测方法。它利用了PSO算法的全局搜索能力和BP神经网络的优化能力&#xff0c;能够更准确地预测时序数据。 具体步…

idea maven 打包 内存溢出 报 GC overhead limit exceeded -> [Help 1]

idea 使用maven打包 报GC overhead limit exceeded -> [Help 1] 解决方法&#xff1a; 打开settings -> 点开如同所示 将 vm Options 参数 设为 -Xmx8g

国内首款AI音乐生成大模型「天工SkyMusic」并开启免费邀测;SWE-agent 修复GitHub仓库中的BUG和问题的软件工程代理

✨ 1: 天工SkyMusic 昆仑万维推出国内首款AI音乐生成大模型「天工SkyMusic」并开启免费邀测 天工SkyMusic是由昆仑万维集团开发的一款AI音乐生成工具&#xff0c;它基于先进的「天工3.0」超级大模型构建&#xff0c;代表了目前国内唯一公开可用的AI音乐生成大模型。这款工具专…

JAVAEE之JavaScript(WebAPI)

1.WebAPI 背景知识 JS 分成三个大的部分 ECMAScript: 基础语法部分&#xff08; JS 基础语法主要学的是 ECMAScript, &#xff09; DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI 就包含了 DOM BOM. 2.API API 是一个更广义的概念 . 而 WebAPI 是一个更具体的…

2024 抖音欢笑中国年(二):AnnieX互动容器创新玩法解析

本文基于24年抖音春节活动业务背景&#xff0c;介绍了字节跨端容器AnnieX在游戏互动套件上的探索&#xff0c;致力于提升容器在游戏互动场景的优化能力。 业务背景 AnnieX作为字节一方游戏统一容器&#xff0c;服务字节内部电商、直播、UG等跨端场景业务。在字节一方游戏互动场…

HarmonyOS NEXT应用开发之MVVM模式

应用通过状态去渲染更新UI是程序设计中相对复杂&#xff0c;但又十分重要的&#xff0c;往往决定了应用程序的性能。程序的状态数据通常包含了数组、对象&#xff0c;或者是嵌套对象组合而成。在这些情况下&#xff0c;ArkUI采取MVVM Model View ViewModel模式&#xff0c;其…

一维数组oj练习(4)

又是一维数组的练习.... 小A的学号在数组中可以看成a[k]&#xff0c;在判断谁大于a[k]。大于的数用sum来统计&#xff0c;最后输出。 #include<cstdio> int a[10010],n,k,sum; int main(){scanf("%d %d",&n,&k);for(int i1;i<n;i){scanf("%d…

鸿蒙OS开发实例:【应用事件打点】

简介 传统的日志系统里汇聚了整个设备上所有程序运行的过程流水日志&#xff0c;难以识别其中的关键信息。因此&#xff0c;应用开发者需要一种数据打点机制&#xff0c;用来评估如访问数、日活、用户操作习惯以及影响用户使用的关键因素等关键信息。 HiAppEvent是在系统层面…

212 基于matlab的双稳态随机共振的算法

基于matlab的双稳态随机共振的算法&#xff0c;分析信噪比随系统参数a,b及乘性噪声和加性噪声的增益变化曲线&#xff0c;60个数据样本可供选择。程序已调通&#xff0c;可直接运行。 212 双稳态随机共振 信噪比增益变化曲线 - 小红书 (xiaohongshu.com)

蓝桥杯第十三届电子类单片机组决赛程序设计

前言 一、决赛题目 1.比赛题目 2.题目解读 二、功能实现 1.关于定时器资源 1&#xff09;超声波和NE555需要的定时器资源 2&#xff09;定时器2 2.单位切换 3.数据长度不足时&#xff0c;高位熄灭 4.AD/DA多通道的处理 5.PWM输出 6.长按功能的实现 三、完整代码演…

基于ssm的轻型卡车零部件销售平台(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的轻型卡车零部件销售平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 轻型卡车零部件销售平台…

【VUE+ElementUI】el-table表格固定列el-table__fixed导致滚动条无法拖动

【VUEElementUI】el-table表格固定列el-table__fixed导致滚动条无法拖动 背景 当设置了几个固定列之后&#xff0c;表格无数据时&#xff0c;点击左侧滚动条却被遮挡&#xff0c;原因是el-table__fixed过高导致的 解决 在index.scss中直接加入以下代码即可 /* 设置默认高…

vue项目引入微信sdk: npm install weixin-js-sdk --save报错

网上查到要用淘宝的镜像 同事告知旧 域名&#xff1a;https://registry.npm.taobao.org/已经不能再使用 使用 npm config set registry http://registry.npmmirror.com

DVWA-File Inclusion通关教程-完结

DVWA-File Inclusion通关教程-完结 文章目录 DVWA-File Inclusion通关教程-完结页面功能LowMediumHighImpossible 页面功能 点击页面上提供的三个页面&#xff0c;单击这些文件就会显示其执行内容&#xff0c;同时发现提交是由GET方式进行&#xff0c;使用page参数传参。 …

商业分析师BA与数据分析有什么关系?

文章主题:BA工作与数据分析 分享嘉宾&#xff1a;丛珊 职业&#xff1a;某事业单位BA分析师 在实际工作中&#xff0c;需求分析工作可以有多种分类方法&#xff0c;对于大型、集成型信息系统的需求分析&#xff0c;通常可以区分为业务需求、功能需求、数据需求、性能需求与安…

Linux TUN设备实现Tunnel性能分析

一、TUN/TAP设备原理&#xff1a; Linux的TUN/TAP设备是一种可以使得应用层与TCP/IP协议栈交互的驱动模块&#xff0c;通常用于组建虚拟局域网中的点对点隧道&#xff08;Tunnel&#xff09;&#xff0c;可以工作于2层&#xff08;TAP设备&#xff09;和3层&#xff08;TUN设备…

【环境变量】命令行参数 | 概念 | 理解 | 命令行参数表 | bash进程

目录 四组概念 命令行参数概念&理解 查看命令函参数 命令行字符串&命令行参数表 命令行参数存在的意义 谁形成的命令行参数 父进程&子进程&数据段 bash进程 最近有点小忙&#xff0c;可能更新比较慢。 四组概念 竞争性: 系统进程数目众多&#xff0c…

了解这些技术:Flutter应用顺利登陆iOS平台的步骤与方法

引言 &#x1f680; Flutter作为一种跨平台的移动应用程序开发框架&#xff0c;为开发者提供了便利&#xff0c;使他们能够通过单一的代码库构建出高性能、高保真度的应用程序&#xff0c;同时支持Android和iOS两个平台。然而&#xff0c;完成Flutter应用程序的开发只是第一步…

【WebKit架构讲解】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…