Android APK pyjnius Error - exposed beyond app through ClipData.Item.getUri()

212 views
Skip to first unread message

Shoumik Das

unread,
Jan 9, 2021, 11:45:38 AM1/9/21
to Kivy users support
Hi, I have built a simple Kivy app which shares pdf files through Email, WhatsApp or other available apps. I tested the sharing code with simple text which worked fine. However, when I try to send a pdf file, my app crashes with the following logcat error:

01-09 21:53:50.743 16702 16895 I python  :    File "/home/neo/code/androidlab/image2pdf/v42/.buildozer/android/app/main.py", line 224, in open_pdf
01-09 21:53:50.743 16702 16895 I python  :    File "jnius/jnius_export_class.pxi", line 1047, in jnius.jnius.JavaMultipleMethod.__call__
01-09 21:53:50.744 16702 16895 I python  :    File "jnius/jnius_export_class.pxi", line 769, in jnius.jnius.JavaMethod.__call__
01-09 21:53:50.745 16702 16895 I python  :    File "jnius/jnius_export_class.pxi", line 863, in jnius.jnius.JavaMethod.call_method
01-09 21:53:50.746 16702 16895 I python  :    File "jnius/jnius_utils.pxi", line 91, in jnius.jnius.check_exception
01-09 21:53:50.746 16702 16895 I python  :  jnius.jnius.JavaException: JVM exception occurred: file:///storage/emulated/0/p3media/20210109215348.pdf exposed beyond app through ClipData.Item.getUri()
01-09 21:53:50.746 16702 16895 I python  : Python for android ended.

This is my Python code:

from jnius import autoclass, cast

def open_pdf(self):
PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
File = autoclass('java.io.File')
shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.setType('application/pdf')
PdfFile = File(self.final_pdf_path)
uri = Uri.fromFile(PdfFile)
parcelable = cast('android.os.Parcelable', uri)
shareIntent.putExtra(Intent.EXTRA_STREAM, parcelable)
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
currentActivity.startActivity(shareIntent)

Can someone please advise what is wrong in my code? I want to be able to share the generated pdf through available apps on my Android phone. Please suggest.


planckp...@gmail.com

unread,
Jan 9, 2021, 12:17:39 PM1/9/21
to Kivy users support
I expect this is the issue (POSIX again), and may be api version related - if you are using >27 try 27 first.

Android now won't let you share a file uri, it has to be a 'content uri'.
Basically the other app does not have read permission of a file uri.
A content uri looks similar (content://whatever) but the 'whatever' is only readable/writable via Android API

You can use the API to read (in practice copy contents) of a content uri from Python.
However p4a does not currently support creating a content uri, which sucks.
Support requires adding a FileProvider to the manifest of a local copy of p4a.

If you want to go this route I have some instructions for modifying p4a.
Currently my example of sharing a content uri is in pieces on the garage floor ;)

Some reading:

planckp...@gmail.com

unread,
Jan 9, 2021, 12:25:03 PM1/9/21
to Kivy users support
This looks like you are trying to address the pdf thing from a previous post.

In between I found this, which I have not yet tried (its on the list...).
Since you are pyjnius fluent it might be easier to build a Kivy widget containing this?
The result would be an embedded pdf viewer.

As I say I have not yet tried it so there may be some issue......

Shoumik Das

unread,
Jan 11, 2021, 2:06:58 AM1/11/21
to Kivy users support
Hi there. I am not fluent in pyjnius. I did some digging around in stackoverflow and got my code to work which was able to invoke the application chooser for sharing "text" only. I tried to tweak this for my pdf (binary object) sharing app but it failed with the error that I have mentioned in my previous post. I also tried with your siggestion of api = 27 but that didn't help. Still get the same error. Following is my working code for text only sharing. The only difference is see between the text sharing and pdf sharing apps is the use of Intent.createChooser. At the moment I don't know how to proceed further. I shall try to use a chooser object and then try again. Shall post my findings here.

from kivy.app import App
from kivy.lang import Builder

from jnius import autoclass
from android.permissions import request_permissions, Permission

PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
String = autoclass('java.lang.String')

root = Builder.load_string('''
Button:
    text: 'Share!'
    on_press: app.share()
''')

class TestApp(App):
    def build(self):
        request_permissions([Permission.READ_EXTERNAL_STORAGE])
        return root

    def share(self):
        intent = Intent()
        intent.setAction(Intent.ACTION_SEND)
        intent.putExtra(Intent.EXTRA_TEXT, String('test share text'))
        intent.setType('text/plain')
        chooser = Intent.createChooser(intent, String('Share...'))
        PythonActivity.mActivity.startActivity(chooser)

if __name__ == '__main__':
    TestApp().run()

planckp...@gmail.com

unread,
Jan 11, 2021, 12:08:40 PM1/11/21
to Kivy users support
Yep, that is exactly the behavior I would expect. I tried the same test cases a while back.

A) I started work on an embedded pdf viewer, looks like it will work. If you want to beta test it for me I can share when it is done.

B) If you want to share a uri follow these instructions , you will then use the FileProvider API to get a content uri from a file.

1) Make a local copy of p4a
---------------------------
Create a (or use existing) directory <some_path> BUT NOT the App directory
Go to https://github.com/kivy/python-for-android/tree/master
From the "Code" button select download a zip file
Unzip and place in the directory <some_path>
In buildozer.spec set, for your value of <some_path>:

p4a.source_dir = <some_path>/python-for-android-master

2) Edit the AndroidManifest file.
---------------------------------
Edit:
<some_path>/python-for-android-master/pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml

Add the following lines at the end of the file, before "</application>"

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="{{ args.package }}.fileprovider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>

3) Specify the folders that can be shared.
------------------------------------------
Create a file 'provider_paths.xml' containing:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="app storage" path="."/>
</paths>

Place it in (create the xml directory) :
<some_path>/python-for-android-master/pythonforandroid/bootstraps/sdl2/build/src/main/res/xml

This example of provider_paths.xml enables sharing of the App local storage.
If you want to share some other location don't ask me, read the docs:
https://developer.android.com/reference/android/support/v4/content/FileProvider.html#SpecifyFiles

4) Include the Java package containing FileProvider in buildozer.spec
---------------------------------------------------------------------

android.gradle_dependencies = "com.android.support:support-core-utils:27.0.0"

Shoumik Das

unread,
Jan 13, 2021, 7:37:49 AM1/13/21
to Kivy users support
Hi there! Sorry for the delayed response. Yes! I would absolutely love to test the pdf viewer for you. Please let me know when it is done. I am also working on the changes that you recommended in the custom p4a for FileProvider. I shall post an update soon.

planckp...@gmail.com

unread,
Jan 15, 2021, 12:04:15 PM1/15/21
to Kivy users support
Try this
main.py
pdfview.py

Shoumik Das

unread,
Jan 16, 2021, 10:40:08 AM1/16/21
to Kivy users support
Your app worked perfectly fine. The app loaded on my phone and when I clicked on the "Tap for PDF" button, it fetched a PDF file and displayed it. I also tested the page flip by swiping left and right and that worked fine as well. I would like to mention, however, that the initial load took a few seconds to complete. However, all subsequent button clicks brought up the pdf file instantly.

This is a life saver for me and exactly the thing I was looking for - a simple pdf viewer. I shall now try to integrate it within my app and shall let you know the results.

Thanks a ton!!

P.S. Your blog/website has pretty impressive content. :-) I do maintain a multi-author blog as a personal hobby.

If you have free time, take a look: https://knowhowspot.com/author/shoumik-das/

Disclaimer: My articles are not as interesting as yours; just random stuff.

planckp...@gmail.com

unread,
Jan 16, 2021, 12:14:30 PM1/16/21
to Kivy users support
😁

Shoumik Das

unread,
Jan 16, 2021, 12:21:30 PM1/16/21
to Kivy users support
I managed to integrate the PdfViewer in my app and it is working fine now. I cannot thank you enough!! I shall now continue to work on the share buttons with the custom p4a build and update my test results here.

VIGNESH KUMAR S

unread,
Feb 14, 2021, 7:43:23 AM2/14/21
to Kivy users support
Did you finished this share pdf?
Reply all
Reply to author
Forward
0 new messages