Flutter安全保护插件aegis_flutter_sdk的使用

Flutter安全保护插件aegis_flutter_sdk的使用

项目介绍

Aegis(读音/ˈiːdʒɪs/) 是腾讯云监控团队提供的前端监控 SDK,涵盖了错误监控,资源测速(img, script, css),接口测速,页面性能(首屏时间)。无需侵入代码,只需引入 SDK 即可自动完成所有监控上报。

在使用 aegis 时无需在业务代码中打点或者做任何其他操作,可以做到与业务代码充分解耦。aegis 将会自动监控前端错误,在错误发生时上报错误的具体情况,帮助您快速定位问题。当您开启资源测速时,aegis 将会自动监听页面资源加载情况(耗费时长、成功率等),并在不影响前端性能的前提下收集前端的性能数据,帮助您快速定位性能短板,提升用户体验。

使用本 SDK 需要配合使用腾讯云前端性能监控 RUM 平台。

快速上手

  1. 前往腾讯云前端性能监控 RUM 平台
  2. 申请项目,申请完成后得到 上报 id,id 在 SDK 初始化的时候会使用。

Aegis SDK 在上报所有数据时都会带上 上报 id,后端服务将根据 上报 id 辨别数据来自哪一个项目,因此,Aegis 建议为每一个项目都单独申请一个 id,如果一个项目下有多个页面,还可以为每一个页面都申请一个项目 id,方便单独查看每一个页面的 PV、错误率、请求错误率等数据。

支持的特性

特性 Android iOS Web
普通日志上报
错误日志上报
白名单日志上报
自定义事件上报
自定义测速
页面加载速度自动测速
离线日志
Http接口测速
钩子函数

发布

运行 dry-run 命令以查看是否都准备 OK 了:

flutter packages pub publish --dry-run

运行 publish 命令正式发布:

flutter packages pub publish

使用SDK

依赖引入

在 Flutter SDK 项目中加入依赖:

dependencies:
  ...
  aegis_flutter_sdk: 

初始化实例

import 'package:aegis_flutter_sdk/aegis_flutter_sdk.dart' 

final aegis = Aegis(
  Config(
    id: 'xxxxx',
    uin: 'xxxxx',
  ),
);

日志上报

创建完 Aegis 实例之后,就可以开心的上报日志啦 🥰,日志上报同样简单:

/// aegis.info支持任意类型的参数,包括map, list, string, int等。 如果是object对象,务必提供“toJson方法”
/// 同时可以指定ext1/ext2/ext3(一个或多个)特定参数
aegis.info(
    '我是一条白名单上报的信息,只有在白名单中的用户才会上报哟。你可以在开发者平台把老板、产品、测试统统都加进白名单中。'
);
aegis.info(
    '我是一条白名单上报的信息,只有在白名单中的用户才会上报哟。你可以在开发者平台把老板、产品、测试统统都加进白名单中。',
    ext1: 'xxx',
    ext1: 'xxx',
    ext1: 'xxx'
);
/// aegis.infoAll支持任意类型的参数,包括map, list, string, int等。 如果是object对象,务必提供“toJson方法”
/// 同时可以指定ext1/ext2/ext3(一个或多个)特定参数
aegis.infoAll(
    '我是一条普通的信息,如果上报量很大的话请谨慎使用哟。'
);
aegis.infoAll(
    '我是一条普通的信息,如果上报量很大的话请谨慎使用哟。',
    ext1: 'xxx',
    ext1: 'xxx',
    ext1: 'xxx'
);
/// aegis.report支持任意类型的参数,包括map, list, string, int等。 如果是object对象,务必提供“toJson方法”
/// 同时可以指定ext1/ext2/ext3(一个或多个)特定参数
aegis.report(
    'error'
)
aegis.report(
    'error',
    ext1: 'xxx',
    ext1: 'xxx',
    ext1: 'xxx'
)

aid

Aegis SDK 为每个用户设备分配的唯一标示,会存储在客户端里,用来区分用户,计算 UV 等。aid 只有用户删除 app 才会更新。

算法如下:

void setAid() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String? aid = prefs.getString('AEGIS_ID');
  if (aid != null) {
    bean['aid'] = aid;
    config.setAid(aid);
  } else {
    aid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
        .replaceAllMapped(RegExp(r"[xy]"), (match) {
      int r = Random().nextInt(16);
      int v = match[0] == 'x' ? r : (r & 0x3) | 0x8;
      return v.toRadixString(16);
    });
    prefs.setString('AEGIS_ID', aid);
    bean['aid'] = aid;
    config.setAid(aid);
  }
}

实例方法

Aegis 实例暴露接口简单实用,目前 Aegis 实例有以下方法供您使用:

  • setConfig
  • info
  • infoAll
  • report
  • error
  • reportEvent
  • reportTime
  • time
  • timeEnd

setConfig

该方法用来修改实例配置,比如下面场景:

import 'package:aegis_flutter_sdk/aegis_flutter_sdk.dart'

final aegis = Aegis(
  Config(
    id: 'xxxxx',
    uin: 'xxxxx',
  ),
);

很多情况下,并不能一开始就获取到用户的 uin,而等获取到用户的 uin 才开始实例化 Aegis,如果这期间发生了错误 Aegis 将监听不到。uin 的设置可以在获取到用户的时候:

final aegis = Aegis(
  Config(
    id: 'xxxxx',
    uin: 'xxxxx',
  ),
);
// 拿到uin之后...
aegis.setConfig({
    uin: 'yyyyyyy'
})

setConfig 支持传入的参数包括 uin, aid, version, ext1, ext2, ext3

info、infoAll、report

这三个方法是 Aegis 提供的主要上报手段。

aegis.info('上报一条白名单日志,这两种情况这条日志才会报到后台:1、打开页面的用户在名单中;2、对应的页面发生了错误认真脸');

aegis.infoAll('上报了一条日志,该上报与 info 唯一的不同就在于,所有用户都会上报');

aegis.report('error');

如上接口均可添加可选参数 `ext1`/`ext2`/`ext3` 指定具体的扩展参数

reportEvent

该方法可用来上报自定义事件,平台将会自动统计上报事件的各项指标,诸如:PV、UV、平台分布等…

aegis.reportEvent('XXX请求成功');

reportTime

该方法可用来上报自定义测速,例如:

// 假如‘onload’的时间是1s
aegis.reportTime('onLoad', 1000);

// 或者如果需要使用额外参数,可以传入对象类型参数,ext1,ext2,ext3 会覆盖默认值:
aegis.reportTime('onLoad', 1000,
  ext1: 'ext1', ext2: 'ext2', ext3: 'ext3', from: '');

time、timeEnd

该方法同样可用来上报自定义测速,适用于两个时间点之间时长的计算并上报,例如:

aegis.time('complexOperation');
/**
 * .
 * .
 * 做了很久的复杂操作之后。。。
 * .
 * .
 */
aegis.timeEnd('complexOperation'); /** 此时日志已经报上去了😄**/

白名单

白名单功能是适用于开发者希望对某些特定的用户上报更多的日志,但是又不希望太多上报来影响到全部日志数据,并且减少用户的接口请求次数,因为 TAM 设定了白名单的逻辑。

  1. 白名单用户会上报全部的 API 请求信息,包括接口请求和请求结果。
  2. 白名单用户可以使用 info 接口信息数据上报。
  3. info vs infoAll:在开发者实际体验过程中,白名单用户可以添加更多的日志,并且使用 info 进行上报。infoAll 会对所有用户无差别进行上报,因此可能导致日志量上报巨大。
  4. 通过接口 whitelist 来判断当前用户是否是白名单用户,白名单用户的返回结果会绑定在 aegis 实例上 (aegis.isWhiteList) 用来给开发者使用。
  5. 用了减少开发者使用负担,白名单用户是团队有效,可以在 组织管理-白名单管理 内创建白名单,则团队下全部项目都生效。

页面加载耗时上报

页面加载耗时上报需按如下步骤:

  1. runApp 之前先初始化 Aegis ,并将 configenablePageLoadTime 设置为 true
void main() {
  runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    // 先初始化 Aegis 组件,因为需要计算页面渲染时间
    final aegis = Aegis(
      Config(
        id: 'xxxxx',
        uin: 'xxxxx',
        enablePageLoadTime: true,
      ),
    );

    runApp(MyApp());
  }, (Object error, StackTrace stack) async {
  });
}
  1. MaterialApp 中添加 navigatorObservers,初始化 TAMPageNavigatorObserver()
class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Demo(),
      navigatorObservers: [PageNavigatorObserver()],
    );
  }
}
  1. 启动页面由 SDK 内部命名为了 firstPage,后续其他页面的命名建议在初始化 router 时进行设置,SDK 默认上报为 unknown
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (BuildContext context) {
          return ChangeNotifierProvider<Catalog>(
            create: (context) => Catalog(),
            child: InfiniteListPage(),
          );
        },
        settings: RouteSettings(name: 'InfiniteListPage'),
      ),
    );

钩子函数/错误监控/离线日志

建设中

配置文档

配置 描述
id 必须,string,默认 无。开发者平台分配的项目 key
uin 建议,string。当前用户的唯一标识符,白名单上报时将根据该字段判定用户是否在白名单中,字段仅支持字母数字@=._-,正则表达式: /^[@=.0-9a-zA-Z_-]{1,60}$/
version 可选,string,默认 SDK 版本号。当前上报版本,当页面使用了 PWA 或者存在离线包时,可用来判断当前的上报是来自哪一个版本的代码,仅支持字母数字.,:_-,长度在 60 位以内
delay 可选,int,默认 1000 ms。上报节流时间,在该时间段内的上报将会合并到一个上报请求中。
repeat 可选,int,默认 5。重复上报次数,对于同一个错误超过多少次不上报。
url 可选,string,默认 //aegis.qq.com/collect。日志上报地址
speedUrl 可选,string,默认 //aegis.qq.com/speed。测速日志上报地址
whiteListUrl 可选,string,默认 //aegis.qq.com/collect/whitelist。白名单确认接口。如果想要关闭白名单接口请求,可以传空字符串。
ext1 可选,string,自定义上报的额外维度,上报的时候可以被覆盖。
ext2 可选,string,自定义上报的额外维度,上报的时候可以被覆盖。
ext3 可选,string,自定义上报的额外维度,上报的时候可以被覆盖。

常见问题(FAQ)

  1. 接口请求报错 403 要怎么处理?

接口 403 一般是因为页面域名校验失败导致的,可以检查项目创建时候设置的域名跟实际上报的域名是否一致。如果项目刚刚创建或者修改域名校验,TAM 数据同步需要一定的时间,大概在 1-2min,可以稍微等一下,这段时间用来读一下文档也是不错的。

  1. RUM 自定义测速为什么仅支持 0 - 60000 之间的数据?

之前自定义测速的逻辑是用户上报任意数据,我们对用户数据进行求均值和中位数,然后显示计算后的结果,但是这样带来的问题就是,服务端无法判断脏数据,但是少量脏数据对用户实际数据却会产生非常大的影响,因此我们目前在服务端对用户数据进行了限制,目前只支持 0-60000 内的数据。

  1. RUM 根据哪个字段来计算 UV?

aegis SDK 没有根据用户设置的 uin 来计算 UV,因为如果当前用户没有登录,则无法计算,而且 uin 值由开发者设置,并不完全可靠,还有无法将用户登录前后状态统一起来,因此 aegis SDK 为每个用户独立生成一个 aid 作为用户(设备)的唯一标识,并且存储在 localStorage 里面,不受登录态影响

行为准则(Code Of Conduct)

如何加入(How To Join)

团队介绍(Members)


完整示例 demo

example/lib/main.dart

import 'dart:async';

import 'package:aegis_flutter_sdk/aegis_flutter_sdk.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'infinite_list/catalog.dart';
import 'infinite_list/infinite_list_page.dart';
import 'util/aegis_manager.dart';

void main() {
  runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    // 先初始化 Aegis 组件,因为需要计算页面渲染时间
    AegisManager();

    runApp(MyApp());
  }, (Object error, StackTrace stack) async {
    AegisManager()
        .ageis
        .error('flutter uncaught error, error:$error, stackTrace:$stack');
  });
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Demo(),
      navigatorObservers: [PageNavigatorObserver()],
    );
  }
}

class Demo extends StatelessWidget {
  // 项目id需要在https://tam.woa.com/role/group-projects-manage内申请
  final aegis = AegisManager().ageis;
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo'),
      ),
      body: ListView(
        children: [
          TextButton(
            onPressed: onPressedInfoAll,
            child: Text('aegis.infoAll [日志上报]'),
            style: TextButton.styleFrom(
              primary: Colors.green,
            ),
          ),
          TextButton(
            onPressed: onPressedInfo,
            child: Text('aegis.info [白名单日志上报]'),
            style: TextButton.styleFrom(
              primary: Colors.blue,
            ),
          ),
          TextButton(
            onPressed: onPressedReport,
            child: Text('aegis.report [自定义错误日志上报]'),
            style: TextButton.styleFrom(
              primary: Colors.orange,
            ),
          ),
          TextButton(
            onPressed: onPressedError,
            child: Text('aegis.error [系统级error日志上报]'),
            style: TextButton.styleFrom(
              primary: Colors.red,
            ),
          ),
          TextButton(
            onPressed: onPressedEvent,
            child: Text('aegis.event'),
            style: TextButton.styleFrom(
              primary: Colors.red,
            ),
          ),
          TextButton(
            onPressed: onPressedReporttime,
            child: Text('aegis.reportTime'),
            style: TextButton.styleFrom(
              primary: Colors.teal,
            ),
          ),
          TextButton(
            onPressed: onPressedTime,
            child: Text('aegis.time'),
            style: TextButton.styleFrom(
              primary: Colors.lightGreen,
            ),
          ),
          TextButton(
            onPressed: onPressedTimeEnd,
            child: Text('aegis.timeEnd'),
            style: TextButton.styleFrom(
              primary: Colors.lightGreen,
            ),
          ),
          TextButton(
            onPressed: () {
              openInfiniteListPage(context);
            },
            child: Text('打开无限List流测试上报页面渲染时间'),
            style: TextButton.styleFrom(
              primary: Colors.deepPurple,
            ),
          ),
        ],
      ),
    );
  }

  void onPressedInfo() {
    aegis.info({
      'text': 'test',
      'number': 1,
      'cool': {'a': 3}
    });
  }

  void onPressedReport() {
    aegis.report('report');
  }

  void onPressedInfoAll() {
    aegis.infoAll({
      'text': 'inforest',
      'number': 1,
      'cool': {'a': 3}
    });
  }

  void onPressedError() {
    aegis.error('error');
  }

  void onPressedEvent() {
    aegis.reportEvent('example event 2', ext1: 'testExt1');
  }

  void onPressedReporttime() {
    aegis.reportTime('exampletime2', 1000);
  }

  void onPressedTime() {
    aegis.time('customTime2');
  }

  void onPressedTimeEnd() {
    aegis.timeEnd('customTime2');
  }

  void openInfiniteListPage(BuildContext context) {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (BuildContext context) {
          return ChangeNotifierProvider<Catalog>(
            create: (context) => Catalog(),
            child: InfiniteListPage(),
          );
        },
        settings: RouteSettings(name: 'InfiniteListPage'),
      ),
    );
  }
}

更多关于Flutter安全保护插件aegis_flutter_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter安全保护插件aegis_flutter_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中集成和使用aegis_flutter_sdk插件来进行安全保护的代码示例。aegis_flutter_sdk是一个常用于Flutter应用的安全保护插件,它提供了一系列功能来增强应用的安全性。

首先,你需要在你的pubspec.yaml文件中添加aegis_flutter_sdk依赖:

dependencies:
  flutter:
    sdk: flutter
  aegis_flutter_sdk: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter应用中,你可以按照以下步骤来使用aegis_flutter_sdk

  1. 初始化SDK

在应用启动时,你需要初始化aegis_flutter_sdk。这通常在main.dart文件的MyApp类中完成。

import 'package:flutter/material.dart';
import 'package:aegis_flutter_sdk/aegis_flutter_sdk.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 初始化Aegis SDK
    AegisFlutterSdk.init(
      appId: '你的AppId', // 替换为你的AppId
      appKey: '你的AppKey', // 替换为你的AppKey
      channel: '你的Channel', // 替换为你的Channel,通常是你的应用发布渠道
    );

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}
  1. 使用SDK提供的安全功能

aegis_flutter_sdk提供了多种安全功能,如设备指纹、防篡改检测等。以下是如何使用这些功能的示例:

import 'package:flutter/material.dart';
import 'package:aegis_flutter_sdk/aegis_flutter_sdk.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String deviceFingerprint = '';

  @override
  void initState() {
    super.initState();
    // 获取设备指纹
    _getDeviceFingerprint();
  }

  Future<void> _getDeviceFingerprint() async {
    try {
      String fingerprint = await AegisFlutterSdk.getDeviceFingerprint();
      setState(() {
        deviceFingerprint = fingerprint;
      });
    } catch (e) {
      print('获取设备指纹失败: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '设备指纹: $deviceFingerprint',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                try {
                  bool isTampered = await AegisFlutterSdk.checkAppTamper();
                  if (isTampered) {
                    showDialog(
                      context: context,
                      builder: (context) {
                        return AlertDialog(
                          title: Text('警告'),
                          content: Text('应用检测到被篡改!'),
                          actions: <Widget>[
                            TextButton(
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                              child: Text('确定'),
                            ),
                          ],
                        );
                      },
                    );
                  } else {
                    print('应用未被篡改。');
                  }
                } catch (e) {
                  print('检查应用篡改失败: $e');
                }
              },
              child: Text('检查应用是否被篡改'),
            ),
          ],
        ),
      ),
    );
  }
}

在上面的代码中,我们展示了如何获取设备指纹以及如何检查应用是否被篡改。当然,aegis_flutter_sdk提供了更多的功能,你可以根据文档进一步探索和使用这些功能。

请确保你已经正确配置了aegis_flutter_sdk所需的AppId、AppKey和Channel,这些通常是在你注册和使用该SDK服务时获得的。

希望这个示例能帮助你在Flutter项目中集成和使用aegis_flutter_sdk

回到顶部