【问题标题】:Flutter Directory.systemTemp is not working in the release apkFlutter Directory.systemTemp 在发行版 apk 中不起作用
【发布时间】:2018-06-11 17:41:48
【问题描述】:

我正在尝试从相机捕获图像并将其保存在缓存中(即 Directory.systemTemp 可从 dart.io 包中获得)。它在调试模式下工作正常。但是当我构建发布 apk 并安装时,它不起作用。这是代码:

import 'dart:async';
import 'dart:io';

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

class CameraExampleHome extends StatefulWidget {
  @override
  _CameraExampleHomeState createState() {
    return new _CameraExampleHomeState();
  }
}

/// Returns a suitable camera icon for [direction].
IconData getCameraLensIcon(CameraLensDirection direction) {
  switch (direction) {
    case CameraLensDirection.back:
      return Icons.camera_rear;
    case CameraLensDirection.front:
      return Icons.camera_front;
    case CameraLensDirection.external:
      return Icons.camera;
  }
  throw new ArgumentError('Unknown lens direction');
}

void logError(String code, String message) =>
    print('Error: $code\nError Message: $message');

class _CameraExampleHomeState extends State<CameraExampleHome> {
  CameraController controller;
  String imagePath;

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  Future<List<CameraDescription>> getCameras() async {
    return await availableCameras();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: _scaffoldKey,
      appBar: new AppBar(
        title: const Text('Camera example'),
      ),
      body: FutureBuilder(
        future: getCameras(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:

            case ConnectionState.waiting:
              return new Text('loading...');

            default:
              if (snapshot.hasError)
                return new Text('Error: ${snapshot.error}');
              else {
                if (snapshot.hasData)
                  return createCameraView(context, snapshot);
                else
                  return new Text('Null');
              }
          }
        },
      ),
    );
  }

  /// Display the preview from the camera (or a message if the preview is not available).
  Widget _cameraPreviewWidget() {
    if (controller == null || !controller.value.isInitialized) {
      return const Text(
        'Tap a camera',
        style: const TextStyle(
          color: Colors.white,
          fontSize: 24.0,
          fontWeight: FontWeight.w900,
        ),
      );
    } else {
      return new AspectRatio(
        aspectRatio: controller.value.aspectRatio,
        child: new CameraPreview(controller),
      );
    }
  }

  /// Display the thumbnail of the captured image or video

  /// Display the control bar with buttons to take pictures and record videos.
  Widget _captureControlRowWidget() {
    return new Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      mainAxisSize: MainAxisSize.max,
      children: <Widget>[
        new IconButton(
          icon: const Icon(Icons.camera_alt),
          color: Colors.blue,
          onPressed: controller != null &&
                  controller.value.isInitialized &&
                  !controller.value.isRecordingVideo
              ? onTakePictureButtonPressed
              : null,
        ),
      ],
    );
  }

  /// Display a row of toggle to select the camera (or a message if no camera is available).
  Widget _cameraTogglesRowWidget(var cameras) {
    final List<Widget> toggles = <Widget>[];

    if (cameras.isEmpty) {
      return const Text('No camera found');
    } else {
      for (CameraDescription cameraDescription in cameras) {
        toggles.add(
          new SizedBox(
            width: 90.0,
            child: new RadioListTile<CameraDescription>(
              title:
                  new Icon(getCameraLensIcon(cameraDescription.lensDirection)),
              groupValue: controller?.description,
              value: cameraDescription,
              onChanged: controller != null && controller.value.isRecordingVideo
                  ? null
                  : onNewCameraSelected,
            ),
          ),
        );
      }
    }

    return new Row(children: toggles);
  }

  String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString();

  void showInSnackBar(String message) {
    _scaffoldKey.currentState
        .showSnackBar(new SnackBar(content: new Text(message)));
  }

  void onNewCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) {
      await controller.dispose();
    }
    controller = new CameraController(cameraDescription, ResolutionPreset.high);

    // If the controller is updated then update the UI.
    controller.addListener(() {
      if (mounted) setState(() {});
      if (controller.value.hasError) {
        showInSnackBar('Camera error ${controller.value.errorDescription}');
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      _showCameraException(e);
    }

    if (mounted) {
      setState(() {});
    }
  }

  void onTakePictureButtonPressed() {
    takePicture().then((String filePath) {
      if (mounted) {
        setState(() {
          imagePath = filePath;
          // videoController?.dispose();
          // videoController = null;
        });
        if (filePath != null) showInSnackBar('Picture saved to $filePath');
      }
    });
  }

  Future<String> takePicture() async {
    if (!controller.value.isInitialized) {
      showInSnackBar('Error: select a camera first.');
      return null;
    }
    //final Directory extDir = await getApplicationDocumentsDirectory();
    final Directory extDir = Directory.systemTemp;
    final String dirPath = '${extDir.path}/Pictures/flutter_test';
    await new Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      // A capture is already pending, do nothing.
      return null;
    }

    try {
      await controller.takePicture(filePath);
    } on CameraException catch (e) {
      _showCameraException(e);
      return null;
    }
    return filePath;
  }

  void _showCameraException(CameraException e) {
    logError(e.code, e.description);
    showInSnackBar('Error: ${e.code}\n${e.description}');
  }

  Widget createCameraView(BuildContext context, AsyncSnapshot snapshot) {
    return new Column(
      children: <Widget>[
        new Expanded(
          child: new Container(
            width: MediaQuery.of(context).size.width,
            child: _cameraPreviewWidget(),
          ),
        ),
        _captureControlRowWidget(),
        new Padding(
          padding: const EdgeInsets.all(5.0),
          child: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              _cameraTogglesRowWidget(snapshot.data),
              //_thumbnailWidget(),
            ],
          ),
        ),
      ],
    );
  }
}

class CameraApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new CameraExampleHome(),
    );
  }
}

List<CameraDescription> cameras;

void main() {
  // Fetch the available cameras before initializing the app.

  runApp(new CameraApp());
}

我尝试将目录设置为等待 getApplicationDocumentsDirectory(),如下所示:

final Directory extDir = await getApplicationDocumentsDirectory();
//final Directory extDir = Directory.systemTemp;
final String dirPath = '${extDir.path}/Pictures/flutter_test';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';

然后在调试模式和发布 apk 中保存图片。但是一旦我重新启动应用程序,图片就会丢失。即使重新启动应用程序,我也希望它们可以访问(这是我要使用缓存的主要原因)。

那么当我尝试在应用的发布版本中保存到缓存时出了什么问题?

【问题讨论】:

    标签: android flutter dart-io


    【解决方案1】:

    改用path_provider 包来获取临时路径https://pub.dartlang.org/packages/path_provider

    Directory tempDir = await getTemporaryDirectory();
    String tempPath = tempDir.path;
    

    Directory.systemTemp 应该只在服务器/控制台上使用。

    【讨论】:

    • 如何使用 path_provider 获取缓存路径?
    • 缓存目录似乎没有被覆盖。我开始在github.com/flutter/flutter/blob/master/packages/flutter/lib/src/… 中搜索,但没有找到访问缓存目录的代码。
    • Dude await getTemporaryDirectory() of path_provider 指的是缓存
    • 这里是如何做到这一点的方法:final pathTemp = await getTemporaryDirectory(); 然后myFiles = pathTemp.listSync();
    猜你喜欢
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 2021-08-18
    • 2023-02-03
    • 2016-09-07
    • 2020-07-11
    • 1970-01-01
    • 2021-04-06
    相关资源
    最近更新 更多