We have education app created with Flutter, this app very same to Udemy app features. in this app the course may contain videos lectures of PDF files all things working well except PDF downloading
The situation is: when user click on PDF file name in lectures list, will open download page, it's contain only one button when user click download button, download process start and download notification appear in notifications area after few seconds notification show file link and failed message
I'm not sure what the problem here Note that: the app was published on play & app store, and the PDF file download is fail in test mode and published versions.
the run log file for download process:
E/flutter (27102): #5 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (27102): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (27102): #7 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (27102): #8 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter (27102): #9 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter (27102): #10 _StreamController.add (dart:async/stream_controller.dart:554:5)
E/flutter (27102): #11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
E/flutter (27102):
D/DownloadWorker(27102): Content-Type = application/pdf
D/DownloadWorker(27102): Content-Length = 1165606
D/DownloadWorker(27102): Charset = null
D/DownloadWorker(27102): Content-Disposition = null
D/DownloadWorker(27102): fileName = 7339d9826c027c3facdf76b943e452eb.pdf
W/System.err(27102): java.io.IOException: Permission denied
W/System.err(27102): at java.io.UnixFileSystem.createFileExclusively0(Native Method)
W/System.err(27102): at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
W/System.err(27102): at java.io.File.createNewFile(File.java:1008)
W/System.err(27102): at vn.hunghd.flutterdownloader.DownloadWorker.createDownloadFileWithDirectFilePath(DownloadWorker.java:490)
W/System.err(27102): at vn.hunghd.flutterdownloader.DownloadWorker.downloadFile(DownloadWorker.java:393)
W/System.err(27102): at vn.hunghd.flutterdownloader.DownloadWorker.doWork(DownloadWorker.java:232)
W/System.err(27102): at androidx.work.Worker$1.run(Worker.java:86)
W/System.err(27102): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err(27102): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err(27102): at java.lang.Thread.run(Thread.java:919)
E/DownloadWorker(27102): Create a file using java.io API failed
D/DownloadWorker(27102): Update too frequently!!!!, but it is the final update, we should sleep a second to ensure the update call can be processed
E/flutter (27102): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: setState() called after dispose(): _MyCourseDownloadScreenState#6a6b6(lifecycle state: defunct, not mounted)
E/flutter (27102): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (27102): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (27102): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (27102): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1052:9)
E/flutter (27102): #1 State.setState (package:flutter/src/widgets/framework.dart:1087:6)
E/flutter (27102): #2 _MyCourseDownloadScreenState.initState.<anonymous closure> (package:connect/screens/my_course_download_screen.dart:43:7)
E/flutter (27102): #3 _rootRunUnary (dart:async/zone.dart:1444:13)
E/flutter (27102): #4 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (27102): #5 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (27102): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (27102): #7 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (27102): #8 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter (27102): #9 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter (27102): #10 _StreamController.add (dart:async/stream_controller.dart:554:5)
E/flutter (27102): #11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
E/flutter (27102):
D/Surface (27102): Surface::disconnect(this=0x701217d000,api=1)
D/View (27102): [Warning] assignParent to null: this = android.widget.FrameLayout{f9df83 V.E...... ......ID 0,0-376,125}
I/InputTransport(27102): Destroy ARC handle: 0x708af9a7c0
D/DownloadWorker(27102): Update notification: {notificationId: 3, title: https://connect-elearning.com/newVersion/uploads/lesson_files/7339d9826c027c3facdf76b943e452eb.pdf, status: 4, progress: -1}
W/System.err(27102): java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.io.File.getPath()' on a null object reference
W/System.err(27102): at vn.hunghd.flutterdownloader.DownloadWorker.downloadFile(DownloadWorker.java:394)
W/System.err(27102): at vn.hunghd.flutterdownloader.DownloadWorker.doWork(DownloadWorker.java:232)
W/System.err(27102): at androidx.work.Worker$1.run(Worker.java:86)
W/System.err(27102): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err(27102): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err(27102): at java.lang.Thread.run(Thread.java:919)
I/WM-WorkerWrapper(27102): Worker result FAILURE for Work [ id=99a29ba5-9003-4ef4-9f19-9fda892a3c5b, tags={ flutter_download_task, vn.hunghd.flutterdownloader.DownloadWorker } ]
download page code:
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:connect/models/common_functions.dart';
import 'package:connect/widgets/app_bar_two.dart';
import 'package:file_utils/file_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import '../constants.dart';
class MyCourseDownloadScreen extends StatefulWidget {
static const routeName = '/my-download-screen';
@override
_MyCourseDownloadScreenState createState() => _MyCourseDownloadScreenState();
}
class _MyCourseDownloadScreenState extends State<MyCourseDownloadScreen> {
int progress = 0;
ReceivePort _receivePort = ReceivePort();
static downloadingCallback(id, status, progress) {
///Looking up for a send port
SendPort sendPort = IsolateNameServer.lookupPortByName("downloading");
///ssending the data
sendPort.send([id, status, progress]);
}
@override
void initState() {
super.initState();
IsolateNameServer.registerPortWithName(_receivePort.sendPort, "downloading");
///Listening for the data is coming other isolates
_receivePort.listen((message) {
progress = message[2];
setState(() {
progress = message[2];
});
print(progress);
});
FlutterDownloader.registerCallback(downloadingCallback);
}
@override
Widget build(BuildContext context) {
final selectedUrl = ModalRoute.of(context).settings.arguments as String;
return Scaffold(
appBar: CustomAppBarTwo(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Download File", style: TextStyle(fontSize: 18),),
),
color: Colors.redAccent,
textColor: Colors.white,
onPressed: () async {
final status = await Permission.storage.request();
String externalDir = "";
if (status.isGranted) {
if (Platform.isAndroid) {
externalDir = "/sdcard/download/";
} else {
externalDir = (await getApplicationDocumentsDirectory()).path;
}
try {
FileUtils.mkdir([externalDir]);
final id = await FlutterDownloader.enqueue(
url: selectedUrl,
savedDir: externalDir,
// fileName: "download1234.pdf",
showNotification: true,
openFileFromNotification: true,
);
CommonFunctions.showSuccessToast("Downloading");
} catch(e){
print(e.getMessage());
CommonFunctions.showSuccessToast("Download Error");
}
} else {
print("Permission denied");
}
},
)
],
),
),
);
}
}