flutter开发实战-指纹、面容ID验证插件实现

flutter开发实战-指纹、面容ID验证插件实现
在iOS开发中,经常出现需要指纹、面容ID验证的功能。

指纹、面容ID是一种基于用生物识别技术,通过扫描用户的面部特征来验证用户身份。

一、效果图

在这里插入图片描述
在这里插入图片描述

二、iOS指纹、面容ID验证

在iOS中实现指纹、面容ID验证功能,步骤如下

2.1 info.plist配置

在info.plist中配置允许访问FACE ID权限

<key>NSFaceIDUsageDescription</key>
<string>允许设备访问Face ID</string>

2.2 引入LocalAuthentication

在代码中引入#import <LocalAuthentication/LocalAuthentication.h>

具体代码实现如下

SDAuthID.h

#import <Foundation/Foundation.h>
#import <LocalAuthentication/LocalAuthentication.h>

/**
 *  设备支持的生物验证方式
 */
typedef NS_ENUM(NSUInteger, SDAuthIDSupportType) {
    /**
     *  支持TouchID验证
     */
    SDAuthIDSupportTypeTouchID = 1,
    /**
     *  支持FaceID验证
     */
    SDAuthIDSupportTypeFaceID,
    /**
     *  不支持支持验证
     */
    SDAuthIDSupportTypeNone,
};

/**
 *  TouchID/FaceID 状态
 */
typedef NS_ENUM(NSUInteger, SDAuthIDState){
    
    /**
     *  当前设备不支持TouchID/FaceID
     */
    SDAuthIDStateNotSupport = 0,
    /**
     *  TouchID/FaceID 验证成功
     */
    SDAuthIDStateSuccess = 1,
    
    /**
     *  TouchID/FaceID 验证失败
     */
    SDAuthIDStateFail = 2,
    /**
     *  TouchID/FaceID 被用户手动取消
     */
    SDAuthIDStateUserCancel = 3,
    /**
     *  用户不使用TouchID/FaceID,选择手动输入密码
     */
    SDAuthIDStateInputPassword = 4,
    /**
     *  TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)
     */
    SDAuthIDStateSystemCancel = 5,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置密码
     */
    SDAuthIDStatePasswordNotSet = 6,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID
     */
    SDAuthIDStateTouchIDNotSet = 7,
    /**
     *  TouchID/FaceID 无效
     */
    SDAuthIDStateTouchIDNotAvailable = 8,
    /**
     *  TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)
     */
    SDAuthIDStateTouchIDLockout = 9,
    /**
     *  当前软件被挂起并取消了授权 (如App进入了后台等)
     */
    SDAuthIDStateAppCancel = 10,
    /**
     *  当前软件被挂起并取消了授权 (LAContext对象无效)
     */
    SDAuthIDStateInvalidContext = 11,
    /**
     *  系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)
     */
    SDAuthIDStateVersionNotSupport = 12
};

typedef void (^SDAuthIDStateBlock)(SDAuthIDState state, NSError *error);

 SDAuthID : NSObject

+ (instancetype)sharedInstance;

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics;

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block;


实现的代码

SDAuthID.m

#import "SDAuthID.h"

 SDAuthID

+ (instancetype)sharedInstance {
    static SDAuthID *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[SDAuthID alloc] init];
    });
    return instance;
}

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block {
    
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)");
            block(SDAuthIDStateVersionNotSupport, nil);
        });
        return;
    }
    
    
    LAContext *context = [[LAContext alloc] init];
    // 认证失败提示信息,为 @"" 则不提示
    context.localizedFallbackTitle = localizedFallbackTitle;
    
    NSError *error = nil;
    
    // LAPolicyDeviceOwnerAuthenticationWithBiometrics: 用TouchID/FaceID验证
    // LAPolicyDeviceOwnerAuthentication: 用TouchID/FaceID或密码验证, 默认是错误两次或锁定后, 弹出输入密码界面
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:description reply:^(BOOL success, NSError * _Nullable error) {
            
            if (success) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"TouchID/FaceID 验证成功");
                    block(SDAuthIDStateSuccess, error);
                });
            } else if(error){
                if ((iOS 11.0, *)) {
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID/FaceID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorBiometryLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                } else {
                    // iOS 11.0以下的版本只有 TouchID 认证
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置TouchID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                            //case :{
                        case LAErrorTouchIDNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                }
                
            }
        }];
        
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"当前设备不支持TouchID/FaceID");
            block(SDAuthIDStateNotSupport, error);
        });
    }
}


/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics {
    LAContext *context = [[LAContext alloc] init];
    NSError *error;
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        if (error != nil) {
            return SDAuthIDSupportTypeNone;
        }
        if ((iOS 11.0, *)) {
            return context.biometryType == LABiometryTypeTouchID ?  SDAuthIDSupportTypeTouchID:SDAuthIDSupportTypeFaceID ;
        }
    }
    return SDAuthIDSupportTypeNone;
}


具体使用方式如下;

需要在plist文件中添加 Privacy-Face ID Usage Description 属性
 <key>NSFaceIDUsageDescription</key>
 <string>允许设备访问Face ID</string>

 使用方式
 判断支持的类型
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 
 NSString *description = @"";
 if(SDAuthIDSupportTypeFaceID == supportType){
     description = @"验证已有面容";
 } else if(SDAuthIDSupportTypeTouchID == supportType){
     description = @"通过Home键验证已有指纹";
 } else {
     description = @"不支持TouchID/FaceID";
 }
 
 [[SDAuthID sharedInstance] showAuthIDWithDescription:description localizedFallbackTitle:@"请输入密码" block:^(SDAuthIDState state, NSError *error) {
     if (state == SDAuthIDStateNotSupport) { // 不支持TouchID/FaceID
         NSLog(@"对不起,当前设备不支持指纹/面容ID");
     } else if(state == SDAuthIDStateFail) { // 认证失败
         NSLog(@"指纹/面容ID不正确,认证失败");
     } else if(state == SDAuthIDStateTouchIDLockout) {   // 多次错误,已被锁定
         NSLog(@"多次错误,指纹/面容ID已被锁定,请到手机解锁界面输入密码");
     } else if (state == SDAuthIDStateSuccess) { // TouchID/FaceID验证成功
         NSLog(@"认证成功!");
     }
 }];

三、实现flutter 调用指纹、面容ID插件

3.1、创建flutter plugin

创建flutter plugin,我使用的工具是Android studio。

配置如下内容:

  • Project name
  • Project location
  • Description
  • Project type: Plugin
  • Android language
  • iOS language
  • Platforms

如图所示

在这里插入图片描述

3.2、flutter调用代码实现

flutter 调用原生的代码,需要用到channel,这里使用Method channel

实现调用的platform_interface

import ‘flutter_authid_platform_interface.dart’;

/// An implementation of [FlutterAuthidPlatform] that uses method channels.
class MethodChannelFlutterAuthid extends FlutterAuthidPlatform {
  /// The method channel used to interact with the native platform.
  
  final methodChannel = const MethodChannel('flutter_authid');

  
  Future<String?> getPlatformVersion() async {
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }

  
  Future<Map<dynamic, dynamic>?> getAuthIDSupportType() async {
    final result = await methodChannel.invokeMethod<Map<dynamic, dynamic>>('getAuthIDSupportType');
    return result;
  }

  
  Future<Map<dynamic, dynamic>?> authVerification({Map<dynamic, dynamic>? arguments}) async {
    final result = await methodChannel.invokeMethod<Map<dynamic, dynamic>>('authVerification', arguments);
    return result;
  }
}

调用的platform_interface的具体的类

import ‘flutter_authid_platform_interface.dart’;

class FlutterAuthid {
  Future<String?> getPlatformVersion() {
    return FlutterAuthidPlatform.instance.getPlatformVersion();
  }

  Future<Map<dynamic, dynamic>?> getAuthIDSupportType() {
    return FlutterAuthidPlatform.instance.getAuthIDSupportType();
  }

  ///Map<dynamic, dynamic> arguments = {};
  // arguments['faceAuthDesc'] = "验证已有面容";
  // arguments['touchAuthDesc'] = "通过Home键验证已有指纹";
  // arguments['noSupportAuthDesc'] = "不支持TouchID/FaceID";
  // arguments['fallbackTitle'] = "请输入密码";
  Future<Map<dynamic, dynamic>?> authVerification({Map<dynamic, dynamic>? arguments}) {
    return FlutterAuthidPlatform.instance.authVerification(arguments: arguments);
  }
}

/**
 注意:<key>NSFaceIDUsageDescription</key>
    <string>允许设备访问Face ID</string>
 */

3.3、插件的使用实例Example

在flutter插件的example中实现插件的调用,具体代码如下

class AuthPage extends StatefulWidget {
  const AuthPage({Key? key}) : super(key: key);

  
  State<AuthPage> createState() => _AuthPageState();
}

class _AuthPageState extends State<AuthPage> {
  final _flutterAuthidPlugin = FlutterAuthid();

  String authName = "";
  String authImage = "";
  String hintDescription = "";
  String supportType = "";

  
  void initState() {
    // TODO: implement initState
    super.initState();
    setupAuth();
  }

  Future<void> setupAuth() async {
    Map<dynamic, dynamic> result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      result = await _flutterAuthidPlugin.getAuthIDSupportType() ?? {};
    } on PlatformException {
      result = {};
    }

    print("getAuthIDSupportType:$result");
    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      String type = result['supportType'].toString();
      supportType = type;
      if ("2" == type) {
        authImage = "auth_face@2x.png";
        authName = "面容";
      } else if ("1" == type) {
        authImage = "auth_finger@2x.png";
        authName = "指纹";
      }
      hintDescription = result['desc'];
    });

    authVerification();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Auth app'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Image(
              image: AssetImage("assets/images/$authImage"),
              width: 100.0,
              height: 100.0,
            ),
            SizedBox(height: 50.0,),
            Text(
              'SDAuthApp\n $hintDescription以进行登录',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 18,
                color: Colors.black,
              ),
            ),
            SizedBox(height: 50.0,),
            TextButton(
              onPressed: () {
                authVerification();
              },
              child: Text(
                '点击验证$authName',
                style: TextStyle(
                  fontSize: 17,
                  color: Colors.black,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  // 点击唤起指纹、面容ID验证
  Future<void> authVerification() async {
    Map<dynamic, dynamic> arguments = {};
    arguments['faceAuthDesc'] = "验证已有面容";
    arguments['touchAuthDesc'] = "通过Home键验证已有指纹";
    arguments['noSupportAuthDesc'] = "不支持TouchID/FaceID";
    arguments['fallbackTitle'] = "请输入密码";

    Map<dynamic, dynamic> result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      result =
          await _flutterAuthidPlugin.authVerification(arguments: arguments) ??
              {};
    } on PlatformException {
      result = {};
    }

    print("authVerification:$result");
  }
}

四、小结

flutter开发实战-指纹、面容ID验证插件实现,主要iOS开发中的指纹、面容ID验证功能,通过flutter的插件实现调用原生的插件。

学习记录,每天不停进步。

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

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

相关文章

如何用爬虫实现GPT功能

如何用爬虫实现GPT功能&#xff1f; GPT&#xff08;Generative Pre-trained Transformer&#xff09;和爬虫是两个完全不同的概念和技术。GPT是一种基于Transformer模型的自然语言处理模型&#xff0c;用于生成文本&#xff0c;而爬虫是一种用于从互联网上收集数据的技术。 …

【数据结构与算法】力扣:对称二叉树

对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 来源&#xff1a;…

GlusterFs 分布式复制卷(Distributed-Replicate)性能测试

目录 fio工具参数解释 Glusterfs 和NFS 性能测试 顺序写&#xff1a; 随机写&#xff1a; 顺序读&#xff1a; 随机读&#xff1a; 随机读写&#xff1a; 参数说明&#xff1a; 测试结论&#xff1a; 与NFS对比 压测对比结果 NFS和GlusterFs的优缺点 NFS的优点 NFS…

看完这篇异地多活的改造,我决定和架构师battle一下

1. 简述 异地多活的概念以及为什么要做异地多活这里就不进行概述了。概念性的很多&#xff0c;像什么同城双活、两地三中心、三地五中心等等概念。如果有对这些容灾架构模式感兴趣的可以阅读下这篇文章进行了解&#xff1a;《浅谈业务级灾备的架构模式》。 阅读本篇文章之前&…

脚踏Java知识点

对上节Java的基础语法续讲 三元运算符和if语句格式的区别 语法格式&#xff1a; 三元运算符的语法格式是&#xff1a;(condition) ? expression1 : expression2&#xff1b; if语句的语法格式是&#xff1a; if (condition) { // 执行 expression1 } else { // 执行 express…

API全场景零码测试机器人——ATGen带来“超自动化”测试模式

HDC期间可参与新手入驻华为云Testplan抽奖活动&#xff0c;活动链接在文末 众所周知&#xff0c;软件服务及组件之间的交互主要依赖大量的API接口。以华为云300多个商用云服务为例&#xff0c;平均每个服务含500接口&#xff0c;接口总数高达10万&#xff0c;接口调用上下文业务…

多元回归预测 | Matlab基于鹈鹕算法(POA)优化径向基神经网络(POA-RBF)的数据回归预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于鹈鹕算法(POA)优化径向基神经网络(POA-RBF)的数据回归预测,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清…

IDE /skipping incompatible xxx_d.dll when searching for -lxxx_d

文章目录 概述场景复现用以测试的代码编译器位数不匹配导致?保持编译器类型一致再验证编译器位数的影响MingW下调用OS的库咋不告警?以mingW下使用winSocket为例MingW下网络编程的头文件分析该环境下链接的ws2_32库文件在哪里&#xff1f;mingW为啥可以兼容window下的动态库 概…

【Flutter】Audioplayers 4.1.0 简要使用说明

文章目录 一、前言二、安装和设置三、基本使用1.创建 AudioPlayer 实例2.设置音频源3.控制播放 四、示例代码五、总结 一、前言 Audioplayers 是一个非常实用的 Flutter 插件&#xff0c;它可以帮助我们在 Flutter 应用中播放音频。无论你是想在你的应用中添加背景音乐&#x…

Docker: 改变容器化世界的革命性技术

目录 1.1什么是虚拟化 1.2什么是Docker 1.3容器与虚拟机的比较 1.4Docker组建 2、Docker安装 2.2设置ustc的镜像 2.3Docker的启动与停止 3、docker常用命令 3.1镜像 3.2容器相关命令 1.1什么是虚拟化 在计算机中&#xff0c;虚拟化&#xff08;Vitualization&#x…

如何从一个仪表盘管理多个WordPress网站?

您是否正在寻找一种管理多个WordPress网站的简单方法&#xff1f; 监控多个网站并使其保持更新可能非常耗时。 幸运的是&#xff0c;有几种 WordPress 管理工具可以让您从单个仪表板管理多个 WordPress 网站变得非常容易。这将帮助您节省大量时间&#xff0c;同时使所有 Word…

赋能智能智造-RK3568智能主板助力机器人产业高速发展

机器人作为现代制造业的重要一环&#xff0c;正在以惊人的速度推动着生产效率和智能化水平的提升&#xff0c;它们在生产线上的准确操作和高效工作&#xff0c;为企业带来了巨大的竞争优势。关于工业机器人的编程和控制技术&#xff0c;在过去几年中已经有了很多发展和新的应用…

Coggle 30 Days of ML(23年7月)任务九:学会Bert基础,transformer库基础使用

Coggle 30 Days of ML&#xff08;23年7月&#xff09;任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 说明&#xff1a;在这个任务中&#xff0c;你将学习Bert模型的基础知识&#xff…

【安全】Xsslabs(1~13)基于白盒测试浅析

目录 环境 关卡 level 1 level 2 level 3 level 4 level 5 level 6 level 7 level 8 扩展 level 9 level 10 level 11 level 12 level 13 总结 环境 PHP&#xff1a;php7.3.4nts 中间件&#xff1a;Nginx1.15.11 工具&#xff1a;Hackbar 关卡 level …

计网简答题

答案不保证正确性&#xff0c;仅供参考。 1.有如图所示的以太网&#xff0c;每个交换机的名字及接口号、主机的名字及MAC地址都标明在图中。网络初启动时&#xff0c;两个交换机的转发表都为空&#xff0c;接着先后进行以下MAC帧传输&#xff1a;H1→H5&#xff0c;H3→H2&…

SPEC CPU 2006 在 CentOS 5.0 x86_64 古老系统测试【2】

上一篇 SPEC CPU 2006 在 CentOS 5.0 x86_64 古老系统测试_hkNaruto的博客-CSDN博客 虚拟机时间&#xff0c;一天后获得结果 由于ssh版本太低&#xff0c;采用nc把文件拷贝出来 结果 SPEC CFP2006 Result Copyright 2006-2023 Standard Performance Evaluation Corporatio…

vue3+cesium项目搭建

前言 最近需要在一个Vue3的项目中使用到cesium&#xff0c;对于一个cesium没有太多了解的人来说&#xff0c;还是比较麻烦的&#xff0c;本篇博文就将自己在这个过程踩的坑记录下来&#xff0c;有需要的可以看一下 1、vuecesium框架搭建 2、项目运行起来后&#xff0c;球体不…

IP协议【图解TCP/IP(笔记九)】

文章目录 IP即网际协议IP相当于OSI参考模型的第3层网络层与数据链路层的关系 IP基础知识IP地址属于网络层地址路由控制■ 发送数据至最终目标地址■ 路由控制表 数据链路的抽象化IP属于面向无连接型 IP即网际协议 TCP/IP的心脏是互联网层。这一层主要由IP&#xff08;Internet…

【MySQL系列】在Centos7环境安装MySQL

「前言」文章内容大致是在Centos7环境安装MySQL&#xff0c;演示安装的版本为5.7 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 浮生梦&#xff0c;三生渺渺&#xff0c; 因缘无踪&#xff0c;虽堪恋&#xff0c;何必…

uniapp 微信小程序导航功能(从地址列表内点击某一个地址)

效果图&#xff1a; <template><view class"user"><view class"list"><view class"title">地址列表</view><view class"title-label"><view>名称</view><view>距离&#xff…