Problem
Customer is trying to download the pdf from remote server using URL, save them to external or application directory and then open them in external pdf viewer using intent. Like example in post
https://www.appcelerator.com/blog/2015/08/appcelerator-pdf-viewer-demo/. But throwing following error on Android 8.
[ERROR] : TiFileProxy: (KrollRuntimeThread) [9574,75852] IOException encountered
[ERROR] : TiFileProxy: java.io.FileNotFoundException: /storage/emulated/0/com.edf.mobile/EDF Bill 10 August 2018.pdf (Permission denied)
[ERROR] : TiFileProxy: at java.io.FileOutputStream.open0(Native Method)
[ERROR] : TiFileProxy: at java.io.FileOutputStream.open(FileOutputStream.java:287)
[ERROR] : TiFileProxy: at java.io.FileOutputStream.<init>(FileOutputStream.java:223)
[ERROR] : TiFileProxy: at org.appcelerator.titanium.io.TiFile.getOutputStream(TiFile.java:304)
[ERROR] : TiFileProxy: at org.appcelerator.titanium.io.TiFile.open(TiFile.java:368)
[ERROR] : TiFileProxy: at org.appcelerator.titanium.io.TiFile.write(TiFile.java:414)
[ERROR] : TiFileProxy: at org.appcelerator.titanium.TiFileProxy.write(TiFileProxy.java:331)
[ERROR] : TiFileProxy: at org.appcelerator.kroll.runtime.v8.V8Object.nativeCallProperty(Native Method)
[ERROR] : TiFileProxy: at org.appcelerator.kroll.runtime.v8.V8Object.callProperty(V8Object.java:75)
[ERROR] : TiFileProxy: at org.appcelerator.kroll.KrollProxy.handleMessage(KrollProxy.java:1208)
[ERROR] : TiFileProxy: at android.os.Handler.dispatchMessage(Handler.java:101)
[ERROR] : TiFileProxy: at android.os.Looper.loop(Looper.java:164)
[ERROR] : TiFileProxy: at org.appcelerator.kroll.KrollRuntime$KrollRuntimeThread.run(KrollRuntime.java:117)
Note
The strange problem is not happening to all model of devices. For example
On Android 7
Seems all devices work well. At least, all the test devices are working well.
On Android 8
Moto G device which is on android 8 worked fine.
but others, like Google Pixel or Samsung Note 8, will get above error.
Example code
function testPDF() {
var tempFile = Titanium.Filesystem.getFile(Titanium.Filesystem.isExternalStoragePresent() ? Titanium.Filesystem.externalStorageDirectory : Titanium.Filesystem.applicationDataDirectory, '/' + 'EDF Bill ' + e.source.text + '.pdf');
var appfilepath = tempFile.nativePath;
var url = "http://www.mbta.com/uploadedfiles/Documents/Schedules_and_Maps/Rapid%20Transit%20w%20Key%20Bus.pdf";
var xhr = Ti.Network.createHTTPClient();
xhr.onload = function() {
tempFile.write(this.responseData);
try{
Ti.Android.currentActivity.startActivity(Ti.Android.createIntent({
action: Ti.Android.ACTION_VIEW,
type: 'application/pdf',
data: appfilepath
}));
} catch(e) {
Ti.API.info('error trying to launch activity, e = '+e);
alert('No PDF apps installed!');
}
};
xhr.onerror = function() {
alert("Cannot retrieve PDF from web site") ;
};
xhr.timeout = 10000;
xhr.open("GET", url);
xhr.send();
}
Please check this asap, very important function for customer's app.
It's correct that they need to add the required storage permissions into the
tiapp.xml
. But on later Android versions they also need to request storage permissions: For example, they could amend theironload
to request storage permissions:You will want write permissions too: