Flutter应用发布管理插件appcenter_release_manager的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter应用发布管理插件appcenter_release_manager的使用

pub package License

appcenter_release_manager 是一个用于从您的 iOS 或 Android 应用中直接下载 AppCenter 更新的 Flutter 插件。以下是如何使用该插件的详细说明。

使用预定义的UI

您可以使用 AppcenterReleaseManagerLatestReleases 小部件来显示最新的应用更新信息。API Token 应该具有只读权限。

AppcenterReleaseManagerLatestReleases(
  apiToken: 'your-api-token',
  ownerName: 'your-owner-name',
  appName: 'your-app-name',
)

创建自定义UI

如果您想创建自定义的UI,可以使用 AppCenterReleaseManager 类作为仓库或服务。API Token 应该具有只读权限。

AppCenterReleaseManager(
  apiToken: 'your-api-token',
)

通过URL或发布详情安装

通过发布详情安装

final details = await AppCenterReleaseManager(apiToken: 'your-api-token').getLatestReleaseDetails('owner_name', 'app_name');
AppCenterReleaseManager(apiToken: 'your-api-token').installRelease(details, openAndroidInstallScreen: true, keepAndroidNotification: false);

通过URL安装

final details = await AppCenterReleaseManager(apiToken: 'your-api-token').getLatestReleaseDetails('owner_name', 'app_name');
AppCenterReleaseManager(apiToken: 'your-api-token').installReleaseByUrl(details.installUrl, appName: 'your-app-name', appVersion: 'your-version', openAndroidInstallScreen: true, keepAndroidNotification: false);

安装选项

  • openAndroidInstallScreen:在 Android 上,这将在下载完成后打开安装屏幕。在 iOS 上此选项无效。
  • keepAndroidNotification:在 Android 上,这将在下载完成后保留通知。在 iOS 上此选项无效。如果 openAndroidInstallScreen 设置为 false,则 keepAndroidNotification 会自动设置为 true

全权限访问

如果您希望按所有者拆分所有内容,需要提供一个全权限 API Token。

其他可用方法

API Token 应该具有只读权限。

AppCenterReleaseManager(apiToken: 'your-api-token').getUserDetails(); //全局 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getAllOrganizations(); //全局 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getAllApps(); //全局 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getAllApps(ownerName: 'owner_name'); //全局 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getReleases('owner_name', 'app_name'); //全局/应用 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getReleaseDetails('owner_name', 'app_name', 'id'); //全局/应用 API Token 仅限

AppCenterReleaseManager(apiToken: 'your-api-token').getLatestReleaseDetails('owner_name', 'app_name'); //全局/应用 API Token 仅限

Android 生产环境

此包自动为 Android 8 及以上版本添加了一个额外的权限来安装应用程序。

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

对于大多数情况,您不希望在生产环境中使用此权限。要移除此权限,请在 AndroidManifest.xml 中添加以下行:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="your-package-name">

    <uses-permission
        android:name="android.permission.REQUEST_INSTALL_PACKAGES"
        tools:node="remove" />

</manifest>

通常情况下,您会将此代码放在:

/android/app/src/release/AndroidManifest.xml

但如果您使用了 prodalphabeta 等构建变体,可能需要将其放在:

/android/app/src/prod/AndroidManifest.xml

这样可以确保在 prod 构建变体中移除该权限,而在 betaalpha 构建变体中仍然可以安装更新。

示例代码

以下是一个完整的示例代码,展示了如何使用 appcenter_release_manager 插件。

import 'package:appcenter_release_manager/appcenter_release_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var _index = 0;

  late AppCenterReleaseManager _appCenterReleaseManager;

  @override
  void initState() {
    super.initState();
    _appCenterReleaseManager = AppCenterReleaseManager(apiToken: 'your-api-token');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          systemOverlayStyle: SystemUiOverlayStyle.light,
          title: const Text('AppCenter App'),
        ),
        body: IndexedStack(
          index: _index,
          children: [
            OwnerList(appCenterReleaseManager: _appCenterReleaseManager),
            AppList(appCenterReleaseManager: _appCenterReleaseManager),
            AppCenterReleaseManagerLatestReleases(
              apiToken: _appCenterReleaseManager.apiToken,
              ownerName: 'your-owner-name',
              appName: 'your-app-name',
            ),
            UserDetails(appCenterReleaseManager: _appCenterReleaseManager),
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _index,
          onTap: (value) => setState(() => _index = value),
          selectedItemColor: Colors.blue,
          unselectedItemColor: Colors.grey,
          showSelectedLabels: true,
          showUnselectedLabels: true,
          items: const [
            BottomNavigationBarItem(
              icon: Icon(Icons.group),
              label: 'Owners',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.list),
              label: 'Apps',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.description),
              label: 'Latest Releases',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.person),
              label: 'User Details',
            ),
          ],
        ),
      ),
    );
  }
}

class UserDetails extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;

  const UserDetails({
    required this.appCenterReleaseManager,
    super.key,
  });

  @override
  State<UserDetails> createState() => _UserDetailsState();
}

class _UserDetailsState extends State<UserDetails> {
  User? _user;

  @override
  void initState() {
    super.initState();
    _getUserDetails();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        Text('Name: ${_user?.name}'),
        Text('displayName: ${_user?.displayName}'),
        Text('origin: ${_user?.origin}'),
        Text('avatarUrl: ${_user?.avatarUrl}'),
        Text('createdAt: ${_user?.createdAt}'),
        Text('canChangePassword: ${_user?.canChangePassword}'),
      ],
    );
  }

  Future<void> _getUserDetails() async {
    _user = await widget.appCenterReleaseManager.getUserDetails();
    setState(() {});
  }
}

class OwnerList extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;

  const OwnerList({
    required this.appCenterReleaseManager,
    super.key,
  });

  @override
  State<OwnerList> createState() => _OwnerListState();
}

class _OwnerListState extends State<OwnerList> {
  var _list = <Owner>[];

  @override
  void initState() {
    super.initState();
    _getApps();
  }

  Future<void> _getApps() async {
    _list = await widget.appCenterReleaseManager.getAllOrganizations();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _list.length,
      itemBuilder: (context, index) {
        final item = _list[index];
        return ListTile(
          leading: Container(
            width: 64,
            height: 64,
            padding: const EdgeInsets.all(4),
            child: item.avatarUrl == null
                ? const Placeholder()
                : Image.network(item.avatarUrl!),
          ),
          title: Text(item.name),
          onTap: () => Navigator.of(context).push<void>(
            MaterialPageRoute(
              builder: (context) => OwnerAppList(
                appCenterReleaseManager: widget.appCenterReleaseManager,
                owner: item,
              ),
            ),
          ),
        );
      },
    );
  }
}

class OwnerAppList extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;
  final Owner owner;

  const OwnerAppList({
    required this.appCenterReleaseManager,
    required this.owner,
    super.key,
  });

  @override
  State<OwnerAppList> createState() => _OwnerAppListState();
}

class _OwnerAppListState extends State<OwnerAppList> {
  var _list = <App>[];

  @override
  void initState() {
    super.initState();
    _getApps();
  }

  Future<void> _getApps() async {
    _list = await widget.appCenterReleaseManager.getAllApps(ownerName: widget.owner.name);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        systemOverlayStyle: SystemUiOverlayStyle.light,
        title: Text(widget.owner.name),
      ),
      body: ListView.builder(
        itemCount: _list.length,
        itemBuilder: (context, index) {
          final item = _list[index];
          return ListTile(
            leading: Container(
              width: 64,
              height: 64,
              padding: const EdgeInsets.all(4),
              child: item.iconUrl == null
                  ? const Placeholder()
                  : Image.network(item.iconUrl!),
            ),
            title: Text(item.name),
            onTap: () => Navigator.of(context).push<void>(
              MaterialPageRoute(
                builder: (context) => AppDetail(
                  appCenterReleaseManager: widget.appCenterReleaseManager,
                  app: item,
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class AppList extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;

  const AppList({
    required this.appCenterReleaseManager,
    super.key,
  });

  @override
  State<AppList> createState() => _AppListState();
}

class _AppListState extends State<AppList> {
  var _list = <App>[];

  @override
  void initState() {
    super.initState();
    _getApps();
  }

  Future<void> _getApps() async {
    _list = await widget.appCenterReleaseManager.getAllApps();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _list.length,
      itemBuilder: (context, index) {
        final item = _list[index];
        return ListTile(
          leading: Container(
            width: 64,
            height: 64,
            padding: const EdgeInsets.all(4),
            child: item.iconUrl == null
                ? const Placeholder()
                : Image.network(item.iconUrl!),
          ),
          title: Text(item.name),
          onTap: () => Navigator.of(context).push<void>(
            MaterialPageRoute(
              builder: (context) => AppDetail(
                appCenterReleaseManager: widget.appCenterReleaseManager,
                app: item,
              ),
            ),
          ),
        );
      },
    );
  }
}

class AppDetail extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;
  final App app;

  const AppDetail({
    required this.appCenterReleaseManager,
    required this.app,
    super.key,
  });

  @override
  State<AppDetail> createState() => _AppDetailState();
}

class _AppDetailState extends State<AppDetail> {
  var _list = <Release>[];

  @override
  void initState() {
    super.initState();
    _getApps();
  }

  Future<void> _getApps() async {
    final name = widget.app.owner?.name;
    if (name == null) return;
    _list = await widget.appCenterReleaseManager.getReleases(name, widget.app.name);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        systemOverlayStyle: SystemUiOverlayStyle.light,
        title: Text(widget.app.name),
      ),
      body: ListView.builder(
        itemCount: _list.length,
        itemBuilder: (context, index) {
          final item = _list[index];
          return ListTile(
            title: Text('${item.shortVersion} (${item.version})'),
            subtitle: Text(item.uploadedAt?.toIso8601String() ?? ''),
            onTap: () => Navigator.of(context).push<void>(
              MaterialPageRoute(
                builder: (context) => ReleaseDetailScreen(
                  appCenterReleaseManager: widget.appCenterReleaseManager,
                  app: widget.app,
                  release: item,
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class ReleaseDetailScreen extends StatefulWidget {
  final AppCenterReleaseManager appCenterReleaseManager;
  final App app;
  final Release release;

  const ReleaseDetailScreen({
    required this.appCenterReleaseManager,
    required this.app,
    required this.release,
    super.key,
  });

  @override
  State<ReleaseDetailScreen> createState() => _ReleaseDetailScreenState();
}

class _ReleaseDetailScreenState extends State<ReleaseDetailScreen> {
  ReleaseDetail? _details;

  @override
  void initState() {
    super.initState();
    _getApps();
  }

  Future<void> _getApps() async {
    final name = widget.app.owner?.name;
    if (name == null) return;
    _details = await widget.appCenterReleaseManager.getReleaseDetails(name, widget.app.name, widget.release.id);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        systemOverlayStyle: SystemUiOverlayStyle.light,
        title: Text(widget.app.name),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: _details == null
            ? []
            : [
                Text(_details!.uploadedAt?.toIso8601String() ?? ''),
                Text('${_details!.shortVersion} (${_details!.version})'),
                MaterialButton(
                  color: Colors.blue,
                  onPressed: () => widget.appCenterReleaseManager.installRelease(
                    _details!,
                    openAndroidInstallScreen: true,
                    keepAndroidNotification: true,
                  ),
                  child: const Text(
                    'Install',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ],
      ),
    );
  }
}

以上代码展示了如何使用 appcenter_release_manager 插件来管理应用的发布和更新。希望对您有所帮助!


更多关于Flutter应用发布管理插件appcenter_release_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter应用发布管理插件appcenter_release_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 appcenter_release_manager 插件在 Flutter 应用中进行发布管理的代码示例。这个插件允许你通过 Microsoft App Center 管理应用的发布。

首先,确保你已经在 pubspec.yaml 文件中添加了 appcenter_release_manager 依赖项:

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

然后,运行 flutter pub get 以获取依赖项。

初始化 App Center

在你的 Flutter 应用中,你需要初始化 App Center。这通常在 main.dart 或一个初始化文件中完成。

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化 App Center
  await AppCenterReleaseManager.install(
    appId: '你的AppCenter应用ID',
    secret: '你的AppCenter应用密钥',
    debug: false, // 生产环境中设置为false
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter AppCenter Release Manager Example'),
        ),
        body: Center(
          child: Text('Check the console for release updates!'),
        ),
      ),
    );
  }
}

监听版本更新

你可以使用 AppCenterReleaseManager.addListener 方法来监听版本更新事件。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化 App Center
  await AppCenterReleaseManager.install(
    appId: '你的AppCenter应用ID',
    secret: '你的AppCenter应用密钥',
    debug: false, // 生产环境中设置为false
  );

  // 添加监听器
  AppCenterReleaseManager.addListener((event) {
    if (event is ReleaseUpdateAvailableEvent) {
      // 处理版本更新可用事件
      print('A new release is available: ${event.releaseNotes}');
      // 显示对话框或导航到更新页面
    } else if (event is ReleaseDownloadProgressEvent) {
      // 处理下载进度事件
      print('Download progress: ${event.progress}%');
    } else if (event is ReleaseInstalledEvent) {
      // 处理版本安装完成事件
      print('New release installed successfully.');
      // 可以重新启动应用
    } else if (event is ReleaseErrorEvent) {
      // 处理错误事件
      print('Error occurred: ${event.error.message}');
    }
  });

  runApp(MyApp());
}

强制检查更新

你可以在需要的时候调用 AppCenterReleaseManager.checkForUpdates() 方法来强制检查更新。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter AppCenter Release Manager Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Check the console for release updates!'),
              ElevatedButton(
                onPressed: () async {
                  // 强制检查更新
                  await AppCenterReleaseManager.checkForUpdates();
                },
                child: Text('Check for Updates'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项

  1. 安全性:确保你的 appIdsecret 不要硬编码在客户端代码中,最好通过安全的后端服务获取。
  2. 用户体验:在提示用户更新时,确保有良好的用户体验,比如提供取消选项,或者在下载和安装过程中提供明确的进度反馈。
  3. 测试:在发布到生产环境之前,务必在测试环境中充分测试发布管理功能。

通过上述代码示例,你应该能够在 Flutter 应用中成功集成和使用 appcenter_release_manager 插件进行发布管理。

回到顶部