I’m working on a Flutter project where I’ve integrated a Power BI report. The report is generated based on an API call that I make, and it displays correctly in my app using a WebView package. The UI of the Power BI report includes an export option to download the report as a PDF.
However, I’m facing an issue when trying to download the PDF. When I click on the export option, Power BI generates the PDF file and displays it as a decoded PDF, but I’m unable to download it directly using Flutter. I have also ensured the permissions to my app
Despite this, the PDF is not being downloaded.
Has anyone faced a similar issue or have any idea how to resolve this?
here’s my code implementation
type here
class SalesOrderReportScreen extends StatefulWidget {
final String reportId;
final Map<String, String> params;
const SalesOrderReportScreen({
required this.reportId,
required this.params,
});
@override
_SalesOrderReportState createState() => _SalesOrderReportState();
}
class _SalesOrderReportState extends State<SalesOrderReportScreen> {
late WebViewController controller;
String reportUrl = '';
@override
void initState() {
super.initState();
String baseUrl = 'https://thisis.baseurl.com/';
reportUrl = _buildReportUrl(baseUrl, widget.reportId, widget.params);
print("url: $reportUrl");
_initializeWebView();
}
void _initializeWebView() {
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
//todo
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onWebResourceError: (WebResourceError error) {
print('Error loading page: ${error.description}');
},
onNavigationRequest: (NavigationRequest request) {
if (request.url.endsWith('.pdf')) {
_downloadPdf(request.url);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse(reportUrl));
}
String _buildReportUrl(
String baseUrl, String reportId, Map<String, String> params) {
String url = '$baseUrl?reportid=$reportId';
params.forEach((key, value) {
url += '&$key=$value';
});
return url;
}
Future<void> _downloadPdf(String url) async {
if (await Permission.storage.request().isGranted) {
var dio = Dio();
try {
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
String fileName = url.split('/').last;
String filePath = '$appDocPath/$fileName';
await dio.download(url, filePath);
showToastMessage('PDF downloaded to $filePath');
} catch (e) {
print('Error downloading file: $e');
showToastMessage('Error downloading file');
}
} else {
showToastMessage('Storage permission denied');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sales Order Report'),
),
body: WebViewWidget(controller: controller),
);
}
}
I have implemented the logic to handle the PDF download in the _downloadPdf
function. Specifically,
Set up the WebView with a NavigationDelegate
to intercept navigation requests.
Checked if the URL ends with .pdf and then called the _downloadPdf
function.
Requested storage permissions using the permission_handler package.
Used the dio package to download the PDF file and save it to the app’s documents directory.
I expected that clicking the export option in the Power BI report would trigger the download, and the PDF would be saved to the local storage of the device. However, despite these steps, the PDF is not being downloaded, and I am unsure where the issue lies.
1
The code you provided looks good otherwise. Make sure you’ve added necessary flags to AndroidManifest.xml
and Info.plist
files. Try adding these.
AndroidManifest.xml
:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Info.plist
:
<key>NSPhotoLibraryUsageDescription</key>
<string>Need access to save downloaded files.</string>
<key>NSDocumentsFolderUsageDescription</key>
<string>Need access to save downloaded files.</string>
The first key for iOS is optional if you plan to use camera roll to save pics and stuff like that. You can just add the second key for your use case.
1