Save and Open PDF on Android!
-
wrote on 31 Oct 2022, 17:13 last edited by
Hello.. I am saving a PDF file on the Android device as follows:
QString fileName = QFileDialog::getSaveFileName(this, tr("Exportar relatório..."), QString(), tr("PDF (*.pdf);;HTML (*.htm *.html);;Excel (*.csv);;Todos Arquivos (*)")); if(fileName.isEmpty()) return; printer->setOutputFormat(QPrinter::PdfFormat); printer->setOutputFileName(fileName); TE_Rel->document()->print(printer);
This way I use on Windows and now I'm using it on Android.
Apparently the PDF is successfully saved in the APP folder. But I can't view the APP form PDF, which I believe is related to Android permissions.Given this, I'm trying to open the PDF right after saving. I use the following code to try to open it:
QString filePath = fileName; //The file exists at that location, I used the same path to create the pdf QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
However, the PDF is not opened through a standard PDF viewer that is installed on the device.
Any other alternative to save and read PDF on Android?
I use QT 5.14.2.
Thanks. -
wrote on 31 Oct 2022, 17:31 last edited by JoeCFD
add read and write permissions in your AndroidManifess.xml? You can save your files in QStandardPaths::DocumentsLocation
-
wrote on 31 Oct 2022, 17:52 last edited by
I will add the following permissions:
<uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_SETTINGS"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_PROFILE"/>
But apparently it has no effect.
Whenever I save the PDF, the QFileDialog opens, allowing saving only within the APP folder.
Any idea?
-
wrote on 31 Oct 2022, 18:08 last edited by JoeCFD
@JoeCFD said in Save and Open PDF on Android!:
QStandardPaths::DocumentsLocation
you assign this path QStandardPaths::DocumentsLocation to QFileDialog
-
wrote on 31 Oct 2022, 18:36 last edited by
Hello.. Okay. Change to:
QString caminho = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QString fileName = QFileDialog::getSaveFileName(this, tr("Exportar relatório..."), caminho, tr("PDF (*.pdf);;HTML (*.htm *.html);;Excel (*.csv);;Todos Arquivos (*)")); if(fileName.isEmpty()) return;
Now open the "Documents" folder. Saves correctly. But I can't open it with my APP through QDesktopServices
-
wrote on 31 Oct 2022, 18:46 last edited by JoeCFD
not familiar with QDesktopServices. What is the error message?
the following link is a bit old. But it may help a bit.
https://stackoverflow.com/questions/18786919/qt-android-qdesktopservicesopenurl-qurlfromlocalfile-pdf-with
https://bugreports.qt.io/browse/QTBUG-67877 -
wrote on 31 Oct 2022, 20:02 last edited by
W System.err: android.os.FileUriExposedException: file:///storage/emulated/0/Documents/Caduser.pdf exposed beyond app through Intent.getData()
W System.err: at android.os.StrictMode.onFileUriExposed(StrictMode.java:2209)
W System.err: at android.net.Uri.checkFileUriExposed(Uri.java:2402)
W System.err: at android.content.Intent.prepareToLeaveProcess(Intent.java:12108)
W System.err: at android.content.Intent.prepareToLeaveProcess(Intent.java:12057)
W System.err: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1742)
W System.err: at android.app.Activity.startActivityForResult(Activity.java:5473)
W System.err: at android.app.Activity.startActivityForResult(Activity.java:5431)
W System.err: at android.app.Activity.startActivity(Activity.java:5817)
W System.err: at android.app.Activity.startActivity(Activity.java:5770)
W System.err: at org.qtproject.qt5.android.QtNative.openURL(QtNative.java:164)
W System.err: at org.qtproject.qt5.android.QtNative.startQtApplication(Native Method)
W System.err: at org.qtproject.qt5.android.QtNative$7.run(QtNative.java:390)
W System.err: at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
W System.err: at java.lang.Thread.run(Thread.java:1012) -
W System.err: android.os.FileUriExposedException: file:///storage/emulated/0/Documents/Caduser.pdf exposed beyond app through Intent.getData()
W System.err: at android.os.StrictMode.onFileUriExposed(StrictMode.java:2209)
W System.err: at android.net.Uri.checkFileUriExposed(Uri.java:2402)
W System.err: at android.content.Intent.prepareToLeaveProcess(Intent.java:12108)
W System.err: at android.content.Intent.prepareToLeaveProcess(Intent.java:12057)
W System.err: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1742)
W System.err: at android.app.Activity.startActivityForResult(Activity.java:5473)
W System.err: at android.app.Activity.startActivityForResult(Activity.java:5431)
W System.err: at android.app.Activity.startActivity(Activity.java:5817)
W System.err: at android.app.Activity.startActivity(Activity.java:5770)
W System.err: at org.qtproject.qt5.android.QtNative.openURL(QtNative.java:164)
W System.err: at org.qtproject.qt5.android.QtNative.startQtApplication(Native Method)
W System.err: at org.qtproject.qt5.android.QtNative$7.run(QtNative.java:390)
W System.err: at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
W System.err: at java.lang.Thread.run(Thread.java:1012)wrote on 31 Oct 2022, 23:12 last edited by@RenanHm said in Save and Open PDF on Android!:
W System.err: at java.lang.Thread.run(Thread.java:1012)
Have you checked permission on startup?
#ifdef REQUEST_PERMISSIONS_ON_ANDROID #include <QtAndroid> bool requestStoragePermission() { using namespace QtAndroid; SOPermission sop; QStringList permissions = {"android.permission.ACCESS_FINE_LOCATION"}; const QHash<QString, PermissionResult> results = requestPermissionsSync(permissions); auto ok = true; auto i = 0; while (ok && i< permissions.size()) { if (!results.contains(permissions[i]) || results[permissions[i]] == PermissionResult::Denied) { qCritical() << "Couldn't get permission: " << permissions[i]; ok = false; --i; } ++i; } return ok; } #endif
-
wrote on 1 Nov 2022, 12:57 last edited by
Hello.. I performed the test with the function mentioned. Change to permission:
QStringList permissions = {"android.permission.READ_EXTERNAL_STORAGE"};
It is returned to me that it has permission. But without any practical effect.
Searching more.. I found that in the most recent versions of Android it is now necessary to use "Provider".
https://bugreports.qt.io/browse/QTBUG-67877
https://bugreports.qt.io/browse/QTBUG-85238Following the guidelines for using the Provider, I add in the Manifest:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.myapp.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider>
I also include the "filepaths" file in the "xml" folder.
But the error always occurs when opening the APP:E AndroidRuntime: FATAL EXCEPTION: main E AndroidRuntime: Process: com.digitalsof.totallocapp, PID: 4718 E AndroidRuntime: java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk"],nativeLibraryDirectories=[/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/lib/arm64, /data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:8231) E AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:7728) E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7482) E AndroidRuntime: at android.app.ActivityThread.access$1600(ActivityThread.java:310) E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2281) E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:226) E AndroidRuntime: at android.os.Looper.loop(Looper.java:313) E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8669) E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk"],nativeLibraryDirectories=[/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/lib/arm64, /data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] E AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259) E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:379) E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:312) E AndroidRuntime: at android.app.AppComponentFactory.instantiateProvider(AppComponentFactory.java:147) E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:8215) E AndroidRuntime: ... 11 more
Any idea?
-
Hello.. I performed the test with the function mentioned. Change to permission:
QStringList permissions = {"android.permission.READ_EXTERNAL_STORAGE"};
It is returned to me that it has permission. But without any practical effect.
Searching more.. I found that in the most recent versions of Android it is now necessary to use "Provider".
https://bugreports.qt.io/browse/QTBUG-67877
https://bugreports.qt.io/browse/QTBUG-85238Following the guidelines for using the Provider, I add in the Manifest:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.myapp.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider>
I also include the "filepaths" file in the "xml" folder.
But the error always occurs when opening the APP:E AndroidRuntime: FATAL EXCEPTION: main E AndroidRuntime: Process: com.digitalsof.totallocapp, PID: 4718 E AndroidRuntime: java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk"],nativeLibraryDirectories=[/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/lib/arm64, /data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:8231) E AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:7728) E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7482) E AndroidRuntime: at android.app.ActivityThread.access$1600(ActivityThread.java:310) E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2281) E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:226) E AndroidRuntime: at android.os.Looper.loop(Looper.java:313) E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8669) E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk"],nativeLibraryDirectories=[/data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/lib/arm64, /data/app/~~qh7wYdLZU6AvVfgP104ckQ==/com.digitalsof.totallocapp-pzAvkKqAw1X05TWYviFvnA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] E AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259) E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:379) E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:312) E AndroidRuntime: at android.app.AppComponentFactory.instantiateProvider(AppComponentFactory.java:147) E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:8215) E AndroidRuntime: ... 11 more
Any idea?
wrote on 1 Nov 2022, 17:21 last edited by piervalli 11 Jan 2022, 17:23@RenanHm
In the my app I haved inserted in the all permission that we need .
const QStringList m_permissionsNameListAndroid = {"android.permission.ACCESS_FINE_LOCATION","android.permission.ACCESS_COARSE_LOCATION","android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE","android.permission.CHANGE_WIFI_STATE","android.permission.READ_PHONE_STATE","android.permission.ACCESS_WIFI_STATE","android.permission.BLUETOOTH","android.permission.BLUETOOTH_ADMIN","android.permission.VIBRATE","android.permission.RECEIVE_BOOT_COMPLETED"};For Android > 10 I have ceate this function to create an file on directory. So You can test, if you can write on directory. I neved opened a url but I think the way is create a function java.
For example
//https://trendoceans.com/how-to-open-pdf-programmatically-using-intent-in-android/For open the url
public static String directoryDownLoad() {
Context context = m_instance.getApplicationContext();
File path = android.os.Environment.getExternalStoragePublicDirectory(
android.os.Environment.DIRECTORY_DOWNLOADS);
Log.v(m_instance.TAG,"directoryDownLoad"+path.getAbsolutePath());
return path.getAbsolutePath();
}Id
-
wrote on 1 Nov 2022, 19:37 last edited by
I'm managing to save the PDF, as I went above.
The problem is in opening the PDF.From what I researched, the "Provider" should be created and call the native java class through "QAndroidJniObject".
But I can't move forward when I edit the Manifest file as above.
-
I'm managing to save the PDF, as I went above.
The problem is in opening the PDF.From what I researched, the "Provider" should be created and call the native java class through "QAndroidJniObject".
But I can't move forward when I edit the Manifest file as above.
-
@RenanHm
In this case usually I create a basic project with Android Studio to open a pdf. Then you can push the function in activity that you have extended in Qt for Androidwrote on 3 Nov 2022, 12:38 last edited by@piervalli said in Save and Open PDF on Android!:
In this case usually I create a basic project with Android Studio to open a pdf. Then you can push the function in activity that you have extended in Qt for Android
I understood. I am going to try..
-
wrote on 3 Nov 2022, 12:40 last edited by
I'm having the same problem with printing documents on Android... QT doesn't recognize the drivers installed... it just gives the option to save to PDF... Do you know anything about this?
-
I'm having the same problem with printing documents on Android... QT doesn't recognize the drivers installed... it just gives the option to save to PDF... Do you know anything about this?
-
@RenanHm
I am remember that the printer is not supported on Android, I think that you need same way.wrote on 3 Nov 2022, 13:34 last edited by@piervalli Got it.. I'll research about it. Thanks.
1/16