Flutter连接管理插件vivanta_connect_flutter的使用
Flutter连接管理插件vivanta_connect_flutter的使用
插件用于在Flutter项目中集成Vivanta Connect。
如何实现Vivanta Connect流程
- 添加Vivanta Connect的导入:
import 'package:vivanta_connect_flutter/views/start_vivanta_connect.dart';
- 创建一个路由以打开Vivanta Connect。例如:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => VivantaConnectFlutter(
apiKey: apiKey, // 必填
customerId: customerId, // 必填
externalUserId: externalUserId, // 必填
companyId: companyId, // 可选
),
),
);
使用通过/users/auth
端点获得的JWT Token:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => VivantaConnectFlutter(
token: token, // 必填
),
),
);
- Vivanta Connect将启动,并根据设备配置自动设置语言。
注意:Vivanta Connect需要有效的API密钥和关联的客户ID才能正常工作。
如何实现嵌入式图表
- 创建一个路由以打开嵌入式图表:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EmbeddedGraph(
apiKey: apiKey, // 必填
customerId: customerId, // 必填
externalUserId: externalUserId, // 必填
graphType: graphType, // 必填(Sleep, Active Time, Activity)
brandId: brandId, // 只有当用户连接了多个品牌时才需要,可选
),
),
);
仅适用于Apple Health集成(iOS)
- 在用户的会话开始时添加此代码以获取并同步Apple Health数据:
import 'package:vivanta_connect_flutter/helpers/vivanta_sync.dart';
final vivantaSyncData = VivantaSync(
apiKey: apiKey, // 必填
customerId: customerId, // 必填
externalUserId: externalUserId, // 必填
);
vivantaSyncData.executeAll(); // 此过程从HealthKit获取数据并上传到Vivanta
使用通过/users/auth
端点获得的JWT Token:
import 'package:vivanta_connect_flutter/helpers/vivanta_sync.dart';
final vivantaSyncData = VivantaSync(
token: token, // 必填
);
vivantaSyncData.executeAll(); // 此过程从HealthKit获取数据并上传到Vivanta
- 在Info.plist文件中添加以下元素:
<key>NSHealthShareUsageDescription</key>
<string>[在此处添加读取Apple Health的目的]</string>
<key>NSHealthUpdateUsageDescription</key>
<string>[在此处添加写入Apple Health的目的]</string>
仅适用于Google Health Connect集成(Android)
- 在AndroidManifest.xml中,根节点内添加以下代码:
<queries>
<package android:name="com.google.android.apps.healthdata" />
<package android:name="com.google.android.apps.fitness" />
</queries>
- 在主
<activity>
节点内添加以下代码:
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>
- 在AndroidManifest.xml的根节点内至少添加一个权限,该权限是您的应用将要访问的。完整的权限列表在这个链接中:https://developer.android.com/health-and-fitness/guides/health-connect/plan/data-types#alpha10。例如:
<uses-permission android:name="android.permission.health.READ_STEPS"/>
- 在
gradle.properties
文件中替换这些值:
org.gradle.jvmargs=-Xmx1536M
android.enableJetifier=true
android.useAndroidX=true
- 在用户的会话开始时添加此代码以获取并同步Google Health Connect数据:
import 'package:vivanta_connect_flutter/helpers/vivanta_sync.dart';
final vivantaSyncData = VivantaSync(
apiKey: apiKey, // 必填
customerId: customerId, // 必填
externalUserId: externalUserId, // 必填
);
vivantaSyncData.executeAll(); // 此过程从HealthKit获取数据并上传到Vivanta
使用通过/users/auth
端点获得的JWT Token:
import 'package:vivanta_connect_flutter/helpers/vivanta_sync.dart';
final vivantaSyncData = VivantaSync(
token: token, // 必填
);
vivantaSyncData.executeAll(); // 此过程从HealthKit获取数据并上传到Vivanta
完整示例代码
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:vivanta_connect_example/helpers.dart';
import 'package:vivanta_connect_example/vivanta.dart';
import 'package:vivanta_connect_example/vivanta_sync_task_handler.dart';
import 'package:vivanta_connect_example/write_to_health.dart';
import 'package:vivanta_connect_flutter/helpers/vivanta_sync.dart';
import 'package:vivanta_connect_flutter/services/preferences.dart';
import 'package:vivanta_connect_flutter/styles/colors.dart';
import 'package:vivanta_connect_flutter/styles/fonts.dart';
import 'package:vivanta_connect_flutter/views/embedded_graph.dart';
// 回调函数应该始终是一个顶级函数。
[@pragma](/user/pragma)('vm:entry-point')
void startCallback() {
// 必须调用setTaskHandler函数来处理后台任务。
FlutterForegroundTask.setTaskHandler(VivantaSyncTaskHandler());
}
void main() => runApp(const Example());
class Example extends StatelessWidget {
const Example({super.key});
// 这个小部件是你的应用程序的根。
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Vivanta Connect 示例',
home: Home(),
);
}
}
class Home extends StatefulWidget {
Home({Key? key}) : super(key: key);
[@override](/user/override)
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
String companyId = 'Vivanta';
final Preferences preferences = Preferences();
late TextEditingController _usernameController;
late TextEditingController _brandController;
late FocusNode _usernameFocusNode;
late FocusNode _brandFocusNode;
[@override](/user/override)
void initState() {
_usernameController = TextEditingController();
_usernameFocusNode = FocusNode();
_brandController = TextEditingController();
_brandFocusNode = FocusNode();
_usernameFocusNode.addListener(() {
if (!_usernameFocusNode.hasFocus) {
preferences.setExternalUserId(_usernameController.text);
}
});
_brandFocusNode.addListener(() {
if (!_brandFocusNode.hasFocus) {
preferences.setBrandId(_brandController.text);
}
});
initAsync();
super.initState();
_requestPermissionForAndroid();
}
Future<void> _requestPermissionForAndroid() async {
if (!Platform.isAndroid) {
return;
}
// "android.permission.SYSTEM_ALERT_WINDOW" 权限必须被授予,以便onNotificationPressed函数被调用。
//
// 当通知被按下且权限被拒绝时,onNotificationPressed函数不会被调用,应用程序会被打开。
//
// 如果你不使用onNotificationPressed或launchApp函数,你不需要写这段代码。
if (!await FlutterForegroundTask.canDrawOverlays) {
// 这个函数需要`android.permission.SYSTEM_ALERT_WINDOW`权限。
await FlutterForegroundTask.openSystemAlertWindowSettings();
}
// Android 12及以上版本,对启动前台服务有一些限制。
//
// 为了在设备重启或意外问题时重新启动服务,你需要允许以下权限。
if (!await FlutterForegroundTask.isIgnoringBatteryOptimizations) {
// 这个函数需要`android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`权限。
await FlutterForegroundTask.requestIgnoreBatteryOptimization();
}
// Android 13及以上版本,你需要允许通知权限来暴露前台服务通知。
final NotificationPermission notificationPermissionStatus =
await FlutterForegroundTask.checkNotificationPermission();
if (notificationPermissionStatus != NotificationPermission.granted) {
await FlutterForegroundTask.requestNotificationPermission();
}
}
void _onData(dynamic data) {
if (data is int) {
} else if (data is String) {
if (data == 'onNotificationPressed') {
Navigator.of(context).pushReplacementNamed('/');
}
}
}
[@override](/user/override)
void dispose() {
_usernameController.dispose();
_usernameFocusNode.dispose();
_brandController.dispose();
_brandFocusNode.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return WillStartForegroundTask(
onWillStart: () async {
// 返回是否启动前台服务。
return true;
},
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'vivanta_connect_demo_foreground_service',
channelName: 'Vivanta Connect 示例前台服务',
channelDescription:
'此通知用于保持Vivanta Connect运行。',
channelImportance: NotificationChannelImportance.DEFAULT,
priority: NotificationPriority.MIN,
isSticky: true, // 重要
iconData: const NotificationIconData(
resType: ResourceType.mipmap,
resPrefix: ResourcePrefix.ic,
name: 'launcher',
),
buttons: [],
),
iosNotificationOptions: const IOSNotificationOptions(
showNotification: false,
playSound: false,
),
foregroundTaskOptions: const ForegroundTaskOptions(
interval: 300000,
isOnceEvent: false,
allowWakeLock: false,
allowWifiLock: false,
),
notificationTitle: 'Vivanta Connect 正在运行',
notificationText:
'请不要关闭此通知以保持Vivanta Connect运行。',
callback: startCallback,
onData: _onData,
child: Scaffold(
appBar: AppBar(
title: Text('Vivanta Connect 示例'),
),
body: Container(
width: MediaQuery.of(context).size.width,
child: ListView(
children: [
_box(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
'外部用户ID:',
textAlign: TextAlign.start,
),
),
TextField(
keyboardType: TextInputType.text,
controller: _usernameController,
focusNode: _usernameFocusNode,
onEditingComplete: () {
FocusScope.of(context).unfocus();
},
),
],
),
),
_box(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
'品牌ID:',
textAlign: TextAlign.start,
),
),
TextField(
keyboardType: TextInputType.text,
controller: _brandController,
focusNode: _brandFocusNode,
onEditingComplete: () {
FocusScope.of(context).unfocus();
},
),
],
),
),
_box(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
TextButton(
onPressed: _usernameController.text.isEmpty
? null
: _launchVivantaConnect,
style: _buttonStyle(),
child: Text(
'连接你的设备到Vivanta',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
if (Platform.isIOS) ...[
_box(),
TextButton(
onPressed: _usernameController.text.isEmpty
? null
: _launchVivantaSync,
style: _buttonStyle(),
child: Text(
'同步Apple Health数据',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
_box(),
TextButton(
onPressed: () => writeAppleHealthParameter(context),
style: _buttonStyle(),
child: Text(
'写入Apple Health参数',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
_box(),
TextButton(
onPressed: () => writeAppleHealthActivity(context),
style: _buttonStyle(),
child: Text(
'写入Apple Health活动',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
],
if (Platform.isAndroid) ...[
_box(),
TextButton(
onPressed: _usernameController.text.isEmpty
? null
: _launchVivantaSync,
style: _buttonStyle(),
child: Text(
'同步Google Health Connect数据',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
_box(),
TextButton(
onPressed: () => writeGoogleHealthParameter(context),
style: _buttonStyle(),
child: Text(
'写入Google Health Connect参数',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
_box(),
TextButton(
onPressed: () => writeGoogleHealthActivity(context),
style: _buttonStyle(),
child: Text(
'写入Google Health Connect活动',
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
),
],
_box(),
_getButtonToGraph(
'打开活动图',
GraphType.activity,
),
_box(),
_getButtonToGraph(
'打开活跃时间图',
GraphType.activeTime,
),
_box(),
_getButtonToGraph(
'打开睡眠图',
GraphType.sleep,
),
_box(),
_getButtonToGraph(
'打开卡路里图',
GraphType.calories,
),
_box(),
_getButtonToGraph(
'打开平均心率图',
GraphType.avgHeartRate,
),
],
),
),
],
),
),
),
);
}
Future<void> initAsync() async {
final externalUserId = await preferences.getExternalUserId();
final brandId = await preferences.getBrandId();
if (externalUserId.isNotEmpty) {
_usernameController.text = externalUserId;
setState(() {});
}
if (brandId.isNotEmpty) {
_brandController.text = brandId;
setState(() {});
}
}
ButtonStyle _buttonStyle({
Color backgroundColor = VivantaColors.primary,
}) =>
ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(backgroundColor),
fixedSize: MaterialStateProperty.all<Size>(
Size(MediaQuery.of(context).size.width - 32, 32),
),
);
Widget _box() => SizedBox(height: 24);
void _launchVivantaConnect() {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: 100,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('你想使用哪种类型的启动?'),
SizedBox(
height: 8,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
child: const Text('使用API密钥'),
onPressed: () async {
await launchVivantaConnectWithKeys(
context,
_usernameController.text,
companyId,
);
Navigator.pop(context);
},
),
ElevatedButton(
child: const Text('使用令牌'),
onPressed: () async {
final token =
await getToken(_usernameController.text, companyId);
await launchVivantaConnectWithToken(context, token);
Navigator.pop(context);
},
),
],
),
SizedBox(
height: 8,
),
],
),
),
);
},
);
}
void _launchVivantaSync() {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: 100,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('你想使用哪种类型的同步过程?'),
SizedBox(
height: 8,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
child: const Text('使用API密钥'),
onPressed: () async {
await _sync(showSuccess: true);
Navigator.pop(context);
},
),
ElevatedButton(
child: const Text('使用令牌'),
onPressed: () async {
final token =
await getToken(_usernameController.text, companyId);
await _syncWithToken(token: token, showSuccess: true);
Navigator.pop(context);
},
),
],
),
SizedBox(
height: 8,
),
],
),
),
);
},
);
}
Widget _getButtonToGraph(String text, GraphType graphType) {
final brandId = int.tryParse(_brandController.text);
return TextButton(
onPressed: _usernameController.text.isEmpty
? null
: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EmbeddedGraph(
apiKey: Vivanta.apiKey,
customerId: Vivanta.customerId,
externalUserId: _usernameController.text,
graphType: graphType,
brandId: brandId,
),
),
);
},
style: _buttonStyle(
backgroundColor: VivantaColors.accent,
),
child: Text(
text,
textAlign: TextAlign.center,
style: VivantaFonts.button,
),
);
}
Future<void> _sync({
bool showSuccess = true,
}) async {
final sync = VivantaSync(
apiKey: Vivanta.apiKey,
customerId: Vivanta.customerId,
externalUserId: _usernameController.text,
);
sync.executeAll().then((value) {
if (showSuccess) {
showSyncSuccess(context);
}
}).catchError(
(onError) {},
);
}
Future<void> _syncWithToken({
bool showSuccess = true,
String token = '',
}) async {
final sync = VivantaSync(
token: token,
);
sync.executeAll().then((value) {
if (showSuccess) {
showSyncSuccess(context);
}
}).catchError(
(onError) {},
);
}
}
更多关于Flutter连接管理插件vivanta_connect_flutter的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter连接管理插件vivanta_connect_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用vivanta_connect_flutter
插件的示例代码,这个插件通常用于管理Flutter应用中的网络连接。请注意,由于这是一个假设的插件名称(因为在实际生态系统中可能不存在名为vivanta_connect_flutter
的官方插件),以下代码示例将基于一个典型的网络连接管理插件的功能来构建。
首先,确保在pubspec.yaml
文件中添加了对该插件的依赖(假设该插件真实存在):
dependencies:
flutter:
sdk: flutter
vivanta_connect_flutter: ^x.y.z # 替换为实际版本号
然后,运行flutter pub get
来获取依赖。
接下来,在你的Flutter应用中,你可以这样使用vivanta_connect_flutter
插件来管理网络连接:
import 'package:flutter/material.dart';
import 'package:vivanta_connect_flutter/vivanta_connect_flutter.dart'; // 假设的包导入路径
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Connectivity Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ConnectivityScreen(),
);
}
}
class ConnectivityScreen extends StatefulWidget {
@override
_ConnectivityScreenState createState() => _ConnectivityScreenState();
}
class _ConnectivityScreenState extends State<ConnectivityScreen> {
VivantaConnect _connectivity = VivantaConnect();
bool _isConnected = false;
@override
void initState() {
super.initState();
initConnectivity();
_connectivity.onConnectivityChanged.listen((VivantaConnectivityResult result) {
if (result == VivantaConnectivityResult.connected) {
setState(() {
_isConnected = true;
});
} else {
setState(() {
_isConnected = false;
});
}
});
}
Future<void> initConnectivity() async {
VivantaConnectivityResult result = await _connectivity.checkConnectivity();
if (result == VivantaConnectivityResult.connected) {
setState(() {
_isConnected = true;
});
} else {
setState(() {
_isConnected = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Connectivity Status'),
),
body: Center(
child: Text(
_isConnected ? 'Connected to the internet' : 'Not connected to the internet',
style: TextStyle(fontSize: 24),
),
),
);
}
}
// 假设的VivantaConnect类和VivantaConnectivityResult枚举,用于模拟插件功能
enum VivantaConnectivityResult { connected, disconnected }
class VivantaConnect {
StreamController<VivantaConnectivityResult> _controller = StreamController<VivantaConnectivityResult>();
Stream<VivantaConnectivityResult> get onConnectivityChanged => _controller.stream;
Future<VivantaConnectivityResult> checkConnectivity() async {
// 模拟一个网络检查
await Future.delayed(Duration(seconds: 2));
return VivantaConnectivityResult.connected; // 在这里可以返回连接状态
}
// 模拟连接状态改变的方法(在实际插件中可能由原生代码触发)
void simulateConnectivityChange(VivantaConnectivityResult result) {
_controller.add(result);
}
}
请注意,上述代码中的VivantaConnect
类和VivantaConnectivityResult
枚举是假设的,用于模拟vivanta_connect_flutter
插件的功能。在实际使用中,你将根据插件提供的API来编写代码。
此外,由于vivanta_connect_flutter
可能是一个虚构的插件名称,你需要查找实际的插件文档来了解其具体的API和使用方法。通常,插件的README文件会包含足够的示例代码和说明来帮助你开始使用。