Flutter日记或笔记管理插件journify_flutter的使用

Flutter日记或笔记管理插件journify_flutter的使用

journify

警告
该项目目前仅处于Beta阶段,并受Journify的抢先体验条款约束。我们鼓励您尝试此新库。请通过GitHub问题/PR反馈您的意见,并随时提交拉取请求。

journify 是一种轻松将Journify添加到您的Flutter应用中的方法。

支持以下平台:

  • Android
  • iOS
  • MacOS
  • Web

某些目标插件可能不支持所有平台功能。请参阅其各自的平台SDK以获取更多详细信息。

目录


安装

运行以下命令:

flutter pub add journify

导入所需的包:

import 'package:journify/client.dart';

从Pilot升级

在Pilot阶段,我们将此库的包名从analytics重命名为journify。升级到v1版本后需要进行一些更改:

pubspec.yaml文件中,移除analytics包并替换为journify

-   analytics:
-     git:
-       url: https://github.com/journify/journify-flutter-sdk
-       ref: main
-       path: packages/core
+   journify: ^1.0.1

在Dart文件中,将导入语句从package:journify改为package:journify

- import 'package:journify/client.dart';
+ import 'package:journify/client.dart';

权限

Android

在应用的AndroidManifest.xml文件中,添加以下行:

<uses-permission android:name="android.permission.INTERNET"/>

使用

设置客户端

该包提供了一个名为createClient的方法,可以用来创建Journify客户端。此中央客户端管理所有跟踪事件。建议将其作为主应用程序状态类的属性添加。

示例代码:

const writeKey = 'JOURNIFY_API_KEY';
final analytics = createClient(Configuration(writeKey));

必须至少传递writeKey。以下是其他配置选项的列表:

客户端选项

名称 默认值 描述
writeKey(必需) ‘’ 您的Journify API密钥。
debug false 设置为false时,不会生成任何信息日志。
collectDeviceId false 设置为true以自动从DRM API收集Android设备上的设备ID。
flushPolicies count=30,time=20s 控制何时将事件批次发送到插件的刷新策略列表。
apiHost “t.journify.dev/v1” 用于指定区域性的Journify事件端点。
cdnHost cdn-settings.journify.com/v1 用于指定区域性的Journify设置端点。
errorHandler null 自定义错误处理器。默认情况下会将错误记录到标准的Flutter日志中。
trackApplicationLifecycleEvents false 启用自动跟踪应用程序生命周期事件:安装、打开、更新、后台化)。
trackDeeplinks false 启用自动跟踪用户通过深度链接打开应用的行为。*注意:发送此标志时,sdk插件_appsflyer将忽略onAppOpenAttribution
autoAddJournifyDestination true 设置为false以跳过添加JournifyDestination插件。
defaultIntegrationSettings null 如果请求从Journify获取设置失败时使用的插件设置。
maxBatchSize true 一次向API发送的最大事件数量。
appStateStream null 用于覆盖应用程序前台或后台事件流。
requestFactory true 用于覆盖生成HTTP请求的工厂。类型:RequestFactory
storageJson true 启用或禁用自动为序列化库生成JSON文件。

客户端方法

跟踪(Track)

track 方法用于记录用户的任何操作,以及描述这些操作的属性。

方法签名:

Future track(String event: string, {Map<String, dynamic>? properties});

示例使用:

journify.track("View Product", properties: {
  "productId": 123,
  "productName": "Striped trousers"
});

屏幕(Screen)

screen 方法用于记录用户在移动应用中看到的每个屏幕,以及关于屏幕的任何属性。

方法签名:

Future screen(String name: string, {Map<String, dynamic>? properties});

示例使用:

journify.screen("ScreenName", properties: {
  "productSlug": "example-product-123",
});

对于自动屏幕跟踪的设置,请参见下方说明。

标识(Identify)

identify 方法用于将用户与其操作联系起来,并记录有关他们的特征。这包括唯一的用户ID以及您知道的任何可选特征,如电子邮件、姓名等。特性选项可以包含您希望与用户关联的任何信息,但在使用任何保留的用户特征时,请确保仅将其用于其预期含义。所有保留特征均由UserTraits类强类型定义。当使用未列为保留用户特征的特性时,这些特性将归入custom属性下。

方法签名:

Future identify({String? userId, UserTraits? userTraits});

示例使用:

journify.identify(userId: "testUserId", userTraits: UserTraits(
  username: "MisterWhiskers",
  email: "hello@test.com",
  custom: {
    "plan": "premium"
  }
);

组(Group)

group API调用是将个人用户与组关联起来的方式——无论是公司、组织、账户、项目、团队还是其他您想到的类似概念!这包括唯一的组ID以及您了解的任何可选组特征,如公司名称、行业、员工人数等。特性选项可以包含您希望与组关联的任何信息,但在使用任何保留的组特征时,请确保仅将其用于其预期含义。所有保留特征均由GroupTraits类强类型定义。当使用未列为保留用户特征的特性时,这些特性将归入custom属性下。

方法签名:

Future group(String groupId, {GroupTraits? groupTraits});

示例使用:

journify.group("some-company", groupTraits: GroupTraits(
  name: 'journify',
  custom: {
    "region": "UK"
  }
);

别名(Alias)

alias 方法用于合并两个用户身份,有效连接两组用户数据。这是一个高级方法,但在某些目的地成功管理用户身份时是必需的。

方法签名:

Future alias(String newUserId);

示例使用:

journify.alias("user-123");

重置(Reset)

reset 方法清除当前用户和组的库内部状态。这对于允许用户在不同身份之间切换的应用程序非常有用。

注意:每次调用reset时,都会自动生成一个新的匿名ID。

方法签名:

void reset();

示例使用:

journify.reset();

刷新(Flush)

默认情况下,分析数据将在30秒后或当20个事件累积时发送到API,以先发生者为准。如果用户关闭应用后有事件未发送,则会在应用恢复时触发刷新。这些值可以通过flushAtflushInterval配置选项进行修改。您也可以手动触发刷新事件。

方法签名:

Future flush();

示例使用:

journify.flush();

高级清理(Advanced Cleanup)

您可能不需要这个!

如果您需要重新初始化客户端,即在应用程序生命周期中多次调用createClient以创建同一客户端,请在旧客户端上调用此方法以清除任何订阅和计时器。

示例代码:

var analytics = createClient(Configuration(writeKey));

journify.cleanup();

analytics = createClient(Configuration(writeKey));

如果不这样做,旧客户端实例仍然存在并保留计时器,导致所有事件触发两次。

理想情况下,您不应该需要这样做,且journify客户端应在应用程序生命周期中只初始化一次。


自动屏幕跟踪

为每个导航操作发送screen()事件很快就会变得乏味,因此您可能希望全局跟踪导航。为此,您需要将分析导航观察器添加到应用程序的导航观察器中。例如,如果您使用的是MaterialApp类,则可以添加以下内容:

return MaterialApp(navigatorObservers: [
  ScreenObserver()
]);

插件+时间线架构

您可以完全控制事件在上传到journify API之前如何被处理。

为了自定义事件创建后的处理方式,您可以在事件通过的处理管道中创建和放置各种插件。此管道称为时间线。

插件类型

插件类型 描述
before 在事件处理开始前执行。
enrichment 作为事件处理的第一层执行。
destination 在事件开始传递到目的地时执行。
after 在所有事件处理完成后执行。可用于执行清理操作等。
utility 仅在手动调用时执行,如日志记录。

插件可以有自己的本地代码(如iOS独有的analytics_plugin_idfa),也可以包装底层库(如analytics_plugin_firebase,它在幕后使用firebase_corefirebase_analytics)。

目的地插件

journify作为DestinationPlugin已内置。您可以添加任意多个其他目的地插件,并将事件和数据上传到它们,而不仅仅是journify。

或者,如果您更喜欢,可以在设置客户端时传递autoAddSegmentDestination = false。这会阻止SegmentDestination插件自动为您添加。

添加插件

您可以在任何时候通过add()方法添加插件。

示例代码:

import 'package:journify/client.dart';
import 'package:journify/event.dart';
import 'package:journify/state.dart';
import 'package:journify_plugin_advertising_id/plugin_advertising_id.dart';
import 'package:journify_plugin_idfa/plugin_idfa.dart';
import 'package:journify_plugin_firebase/plugin_firebase.dart' show FirebaseDestination;

const writeKey = 'Journify_API_KEY';

class _MyAppState extends State<MyApp> {
  final analytics = createClient(Configuration(writeKey));

  @override
  void initState() {
    super.initState();
    initPlatformState();

    analytics
        .addPlugin(FirebaseDestination(DefaultFirebaseOptions.currentPlatform));
    journify.addPlugin(PluginAdvertisingId());
    journify.addPlugin(PluginIdfa());
  }
}

编写自己的插件

插件通过扩展提供的插件类之一来实现。可用的插件类如下:

  • Plugin
  • EventPlugin
  • DestinationPlugin
  • UtilityPlugin
  • PlatformPlugin

任何插件都必须是这些类的扩展。

您可以通过覆盖基类的不同方法来自定义功能。例如,这是一个简单的Logger插件:

import 'dart:convert';

import 'package:journify/journify.dart';
import 'package:journify/event.dart';
import 'package:journify/plugin.dart';
import 'package:journify/logger.dart';

class EventLogger extends DestinationPlugin {
  var logKind = LogFilterKind.debug;

  EventLogger() : super("event_logger");

  @override
  void configure(Analytics analytics) {
    pAnalytics = analytics;
  }

  @override
  Future<RawEvent?>? execute(RawEvent event) async {
    log("${event.type.toString().toUpperCase()} event${event is TrackEvent ? " (${event.event})" : ''} saved: \n${jsonEncode(event.toJson())}",
        kind: logKind);
    return event;
  }
}

由于它覆盖了execute()方法,此Logger将在时间线上每经过一个事件时调用log

支持的插件

以下表格列出了您可以使用的插件以满足您的跟踪需求:

插件 包名
Adjust analytics_plugin_adjust
AppsFlyer analytics_plugin_appsflyer
Firebase analytics_plugin_firebase
IDFA analytics_plugin_idfa
Android Advertising ID analytics_plugin_advertising-id

控制上传的刷新策略

要更细粒度地控制事件的上传时间,您可以使用FlushPolicies

刷新策略定义了决定何时刷新的策略,可以基于间隔、特定时间、接收到一定数量的事件甚至接收到特定事件。这为您提供了更多的灵活性来决定何时将事件发送到journify。

要使用刷新策略,可以在客户端配置中设置它们:

import 'package:journify/flush_policies/count_flush_policy.dart';
import 'package:journify/flush_policies/timer_flush_policy.dart';

final analytics = createClient(Configuration(/*...*/, flushPolicies: [
  CountFlushPolicy(10),
  TimerFlushPolicy(100000)
]));

您可以同时设置多个策略。每当其中任何一个策略决定是时候刷新时,它将触发事件上传。其余策略将重置,以便在每次刷新后重新启动逻辑。

这意味着只有第一个达到shouldFlush的策略能够触发刷新。在上述示例中,事件计数达到5或计时器达到500毫秒,无论哪个先发生,都将触发刷新。

我们有一些标准的刷新策略:

  • CountFlushPolicy:当达到一定数量的事件时触发。
  • TimerFlushPolicy:按毫秒间隔触发。
  • StartupFlushPolicy:仅在客户端启动时触发。

添加或移除策略

刷新策略的主要优点之一是您可以在运行时添加和删除策略。当您想要减少或增加刷新次数时,这非常强大。

例如,如果您检测到用户没有网络连接,您可以禁用刷新:

if (isConnected) {
  journify.addFlushPolicy(policiesIfNetworkIsUp);
} else {
  journify.removeFlushPolicy(policiesIfNetworkIsUp)
}

创建自己的刷新策略

您可以通过实现FlushPolicy接口或扩展FlushPolicyBase类(它已经创建并处理了shouldFlush值的重置)来为您的应用程序需求创建自定义刷新策略。

FlushPolicy只需要实现一个方法:

  • onEvent(RawEvent event):在您的客户端跟踪的每个事件上被调用。

并且可以选择实现以下方法:

  • reset():在刷新触发后调用(由您的策略、另一个策略或手动触发)。
  • start():在刷新策略启用并添加到客户端时执行。这是开始后台操作、进行异步调用、配置执行前事情的好地方。

它们还有一个shouldFlush布尔值。当此值设置为true时,客户端将尝试上传事件。每个策略应根据自己的逻辑将此值重置为false,尽管通常在reset方法中这样做。

示例代码:

import 'package:journify/event.dart';
import 'package:journify/flush_policies/flush_policy.dart';

class FlushOnScreenEventsPolicy extends FlushPolicy {

  @override
  onEvent(RawEvent event) {
    // 仅在发生屏幕事件时刷新
    if (event is ScreenEvent) {
      this.shouldFlush = true;
    }
  }

  @override
  reset() {
    // 超类将重置shouldFlush值,以便下一个屏幕事件再次触发刷新
    // 但您可以在其他事件到来或超时时重置值
    super.reset();
  }
}

自定义日志记录

默认情况下,任何日志记录都是通过标准的Flutter日志机制完成的。要自定义日志记录,您可以构建自己的日志记录器,它必须实现LogTarget混合类。例如:

import 'package:journify/logger.dart';

void customDebugLog(String msg) {
  // ...
}

void customWarningLog(String msg) {
  // ...
}

void customErrorLog(String msg) {
  // ...
}

class CustomLogger with LogTarget {
  @override
  void parseLog(LogMessage log) {
    switch (log.kind) {
      case LogFilterKind.debug:
        customDebugLog("journify: ${log.message}");
        break;
      case LogFilterKind.warning:
        customWarningLog("journify: ${log.message}");
        break;
      case LogFilterKind.error:
        customErrorLog("journify: ${log.message}");
        break;
    }
  }
}

// 将默认日志记录器设置为使用CustomLogger
LogFactory.logger = CustomLogger();

处理错误

您可以通过errorHandler选项处理分析客户端错误。

错误处理程序配置接收一个函数,该函数将在分析客户端发生错误时调用。它将接收一个异常,该异常将扩展来自errors.dart的错误之一。

您可以使用此错误处理程序在出现问题时触发客户端的不同行为。例如,如果客户端受到速率限制,您可以使用错误处理程序来切换刷新策略以减少激进性:

import 'package:journify/errors.dart';

//...

final flushPolicies = [CountFlushPolicy(5), TimerFlushPolicy(500)];

void errorHandler(Exception error) {
  if (error is NetworkServerLimited) {
    // 删除所有刷新策略
    journify.removeFlushPolicy(journify.getFlushPolicies());
    // 添加不太持久的刷新策略
    journify.addFlushPolicy([
      CountFlushPolicy(100),
      TimerFlushPolicy(5000)
    ]);
  }
}

final analytics = createClient(Configuration(writeKey),
  errorHandler: errorHandler,
  flushPolicies: flushPolicies);

从插件报告错误

插件还可以通过使用journify客户端的.error函数报告错误,我们建议使用PluginError保持一致性,并附加innerError以实际捕获的异常:

import 'package:journify/errors.dart';

//...

try {
  distinctId = await mixpanel.getDistinctId();
} catch (e) {
  journify.error(
    PluginError('Error: Mixpanel error calling getDistinctId', e)
  );
}

更多关于Flutter日记或笔记管理插件journify_flutter的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter日记或笔记管理插件journify_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


journify_flutter 是一个用于在 Flutter 应用中集成日记或笔记管理功能的插件。它提供了一系列工具和组件,帮助开发者快速构建日记或笔记应用。以下是如何使用 journify_flutter 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  journify_flutter: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 初始化 Journify

在应用的 main.dart 文件中,初始化 Journify 插件:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化 Journify
  await Journify.initialize(
    apiKey: 'YOUR_API_KEY',  // 替换为你的 API Key
    enableLogging: true,     // 是否启用日志
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Journify Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: JournalScreen(),
    );
  }
}

3. 创建日记或笔记

你可以使用 Journify 提供的 API 来创建日记或笔记。以下是一个简单的示例:

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

class JournalScreen extends StatefulWidget {
  @override
  _JournalScreenState createState() => _JournalScreenState();
}

class _JournalScreenState extends State<JournalScreen> {
  final TextEditingController _titleController = TextEditingController();
  final TextEditingController _contentController = TextEditingController();

  Future<void> _saveJournal() async {
    final String title = _titleController.text;
    final String content = _contentController.text;

    if (title.isNotEmpty && content.isNotEmpty) {
      await Journify.createJournal(
        title: title,
        content: content,
      );

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Journal saved successfully!')),
      );

      _titleController.clear();
      _contentController.clear();
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Please fill in both title and content.')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My Journal'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _titleController,
              decoration: InputDecoration(labelText: 'Title'),
            ),
            SizedBox(height: 16.0),
            TextField(
              controller: _contentController,
              decoration: InputDecoration(labelText: 'Content'),
              maxLines: 5,
            ),
            SizedBox(height: 16.0),
            ElevatedButton(
              onPressed: _saveJournal,
              child: Text('Save Journal'),
            ),
          ],
        ),
      ),
    );
  }
}

4. 获取日记或笔记

你可以使用 Journify.getJournals() 方法来获取所有保存的日记或笔记:

Future<void> _getJournals() async {
  final List<Journal> journals = await Journify.getJournals();
  
  journals.forEach((journal) {
    print('Title: ${journal.title}, Content: ${journal.content}');
  });
}

5. 删除日记或笔记

你可以使用 Journify.deleteJournal() 方法来删除特定的日记或笔记:

Future<void> _deleteJournal(String journalId) async {
  await Journify.deleteJournal(journalId);
}

6. 更新日记或笔记

你可以使用 Journify.updateJournal() 方法来更新特定的日记或笔记:

Future<void> _updateJournal(String journalId, String newTitle, String newContent) async {
  await Journify.updateJournal(
    journalId: journalId,
    title: newTitle,
    content: newContent,
  );
}

7. 处理错误

在使用 Journify 时,可能会遇到错误。你可以使用 try-catch 块来捕获和处理这些错误:

try {
  await Journify.createJournal(
    title: 'My Title',
    content: 'My Content',
  );
} catch (e) {
  print('Error: $e');
}

8. 自定义配置

Journify 提供了一些配置选项,例如日志级别、用户 ID 等。你可以在初始化时或在运行时进行配置:

await Journify.initialize(
  apiKey: 'YOUR_API_KEY',
  enableLogging: true,
  userId: 'USER_ID',  // 可选,用于标识用户
);

9. 事件跟踪

你还可以使用 Journify 来跟踪用户事件,例如用户打开应用的次数、用户点击按钮的次数等:

await Journify.trackEvent('app_opened');
await Journify.trackEvent('button_clicked', properties: {'button_name': 'save_journal'});

10. 用户属性

你可以使用 Journify 来设置用户属性,例如用户的姓名、电子邮件等:

await Journify.setUserProperties({
  'name': 'John Doe',
  'email': 'john.doe@example.com',
});

11. 用户 ID

你可以使用 Journify 来设置用户 ID,以便在分析中跟踪用户:

await Journify.setUserId('USER_ID');

12. 重置用户

如果你想要重置用户数据(例如用户注销时),你可以使用 Journify.reset() 方法:

await Journify.reset();
回到顶部