Android Tutorial Sharing files from your app with File Provider

Discussion in 'Tutorials & Examples' started by Erel, Aug 29, 2016.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Example was updated based on FileProvider class: https://www.b4x.com/android/forum/threads/class-fileprovider-share-files.97865/
    See the above link if you are interested in sharing files from your app.

    This tutorial explains the steps required to implement a file picker that other applications can use to select files or resources.

    upload_2016-8-29_13-51-54.png upload_2016-8-29_13-52-7.png upload_2016-8-29_13-52-19.png

    Starting from Android 7 - Nougat,it is not possible to share a file directly (file:// uri). It will result with a FileUriExposedException. This is relevant even if you don't set the targetSdkVersion to 24.

    The solution is to use FileProvider from Android support library.

    The steps required are:
    1. Add an intent filter that will tell the OS that your app allows choosing content:
    Code:
    'manifest editor.
    'FilePicker is the name of the activity.
    AddActivityText(FilePicker,
    <
    intent-filter>
      <action android:name=
    "android.intent.action.PICK" />
      <category android:name=
    "android.intent.category.DEFAULT" />
      <data android:mimeType=
    "image/*" />
    </
    intent-filter>
    <
    intent-filter>
      <action android:name=
    "android.intent.action.GET_CONTENT" />
      <category android:name=
    "android.intent.category.DEFAULT" />
      <category android:name=
    "android.intent.category.OPENABLE" />
      <data android:mimeType=
    "image/*" />
    </
    intent-filter>
    )

    3. When the relevant activity is resumed it needs to check the starting intent type. If it is an android.intent.action.GET_CONTENT intent then it should allow the user to select the resource.

    4. The resource is copied to the "shared" folder and a Uri is created and returned to the calling app.

    See the attached example.

    Tips:

    - Make sure to run the app in release mode as the process might be killed when it is in the background.
    - This solution is compatible with Android 4+ devices.
     

    Attached Files:

    Last edited: Oct 3, 2018
  2. JohnC

    JohnC Well-Known Member Licensed User

    Hey Erel,

    First, thank you very much for whipping this up so quickly!

    Second, is the secure file sharing aspect of this sample the only thing that requires Android 4+ devices? Or, can I still use the PICK and GET_CONTENT intents and be able to share a file using a direct URI on <4 devices? And if so, how would I modify the provider definition to alternatively provide this direct URI on <4 devices?
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    Yes. Android 2.x devices are mostly not relevant anymore (https://developer.android.com/about/dashboards/index.html). You can return return a file:// uri in the intent instead of using FileProvider to create it.
     
  4. JohnC

    JohnC Well-Known Member Licensed User

    Thank Erel.

    I don't know how you get all the stuff you do done in the time you do it. You have to be using a cloning machine :)
     
    iCAB likes this.
  5. JohnC

    JohnC Well-Known Member Licensed User

    I wonder if using this new file sharing method will allow me to remove the STORAGE permission from my app because I am currently using a direct URI to send a file to the device's MMS using an intent...Hmmm
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    1. I've updated the example. It didn't add the storage permission for Android 4.3- devices.

    2. The example above doesn't need any permission on Android 4.4+ devices. You can read more about it in the runtime permissions tutorial.
     
  7. JohnC

    JohnC Well-Known Member Licensed User

    Darn, I was hoping this method used some sort of "safe" external_storage location so that I could share a file with another app without having to declare the STORAGE permission.

    I know that I can use runtime permissions, but if my app absolutely needs to use the external_storage to operate, then what's the difference between asking/telling the user when they install my app vs. asking them when they run it. My understanding of runtime permissions is that it is good for apps that can still be useful in a "crippled" manner even if one or more permissions were denied by the user. But with my app, External_Storage is mandatory for it to do it's main function.
     
  8. Erel

    Erel Administrator Staff Member Licensed User

    No permission is required when you run this example on Android 4.4+ devices. You can read more about it in the runtime permissions tutorial.
    For further discussion please start a new thread in the questions forum.
     
  9. ivan.tellez

    ivan.tellez Active Member Licensed User

    Ok, I understand how to implement a file picker that other applications can use to select files or resources created with my app.

    But, if I want to share a file created by my app, what is the best aproach?


    Thanks
     
  10. Erel

    Erel Administrator Staff Member Licensed User

  11. peggjones

    peggjones Active Member Licensed User

    Try as I might I can't get this to compile. I get -

    Error parsing manifest script:
    Line = 35, Word = C
    Command expected.

    Where line 35 is CreateResource(xml, provider_paths,

    Obviously missing something any ideas anyone?

    Thanks
     
  12. JohnC

    JohnC Well-Known Member Licensed User

    Sometimes line number reported in the error is not the actual line of the error, but it could be within +/- 5 lines.
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    Which version of B4A are you using?
     
  14. peggjones

    peggjones Active Member Licensed User

    I believe it is 5.20.
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    CreateResource keyword was added in a newer version. You will need to remove it and instead create the XML resource file (make sure to set it to be read-only).
     
    peggjones likes this.
  16. Robert Valentino

    Robert Valentino Well-Known Member Licensed User

    trying to understand the CreateResource keyword

    Code:
    CreateResource(xml, provider_paths,
       <external-files-
    path name="name" path="shared" />
    tried to search on it and found nothing.

    What is xml, provider_paths and external-files-path better yet what are my Options?

    I am trying to share a few string values, plus trying to learn how this could help me in the future

    BobVal
     
    Last edited: Feb 15, 2017
  17. Erel

    Erel Administrator Staff Member Licensed User

    Please start a new thread for this question.
     
  18. Star-Dust

    Star-Dust Expert Licensed User

    Thanks Erel, it works perfectly. I have updated almost all my Apps with the new features.

    As usual with Samsung I have problems .. But I will open a special thread
     
  19. JohnC

    JohnC Well-Known Member Licensed User

    OK, I am concerned with the above statement because my app "shares"(sends) a file to the device's default MMS app via an Intent and it currently uses this method to do it:
    Code:
    iIntent.PutExtra("android.intent.extra.STREAM", CreateUri("file://" & File.Combine(Starter.SafeDir, Filename)))

    Sub CreateUri(uri As StringAs Object
        
    Dim r As Reflector
        
    Return r.RunStaticMethod("android.net.Uri""parse"Array As Object(uri), Array As String("java.lang.String"))
    End Sub
    And this works on 4.4 and 7.1 and 8.x devices.

    So, why does this method, which uses "File://" work on 7.x and higher devices?

    (p.s. The Starter.SafeDir = "rp.GetSafeDirDefaultExternal("shared")" )
     
  20. DonManfred

    DonManfred Expert Licensed User

    i guess you use targetsdk lower than 25. Set it to 26 to check it right.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice