Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand how to see ContentProvider through FileProvider

2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "how to understand ContentProvider through FileProvider". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand how to watch ContentProvider through FileProvider.

Preface

Android7.0,Android improves the privacy of applications and restricts the sharing of files between applications. If you need to share between applications, you need to grant temporary access to the URI you want to access.

The following is the official statement:

For Android-oriented applications, the StrictMode API policy implemented by the Android framework prohibits the disclosure of file:// URI outside your application. If an intent containing the file URI leaves your application, the application fails with a FileUriExposedException exception. To share files between applications, you should send a content:// URI and grant temporary access to URI. The easiest way to do this authorization is to use the FileProvider class. "

Why restrict file sharing between applications

For example, App A has a file whose absolute path is file:///storage/emulated/0/Download/photo.jpg.

Now App A wants to accomplish some requirements through other applications, such as taking photos, so he sends his file path to Photo App B, and then App B saves the photos to this absolute path after taking photos.

There seems to be no problem, but what if app B is a "bad app"?

The file path is disclosed, that is, the privacy of the application.

What if this app An is a "bad app"?

You can use application B to achieve this dangerous permission to store files without applying for storage permission.

It can be seen that this previously outdated plan, from itself to the other side, is not a very good choice.

So Google came up with a way to limit access to files within the application.

If you want to share a file path, don't share the absolute path of a file like file:// URI, but share content:// URI, this relative path, that is, this format: content://com.jimu.test.fileprovider/external/photo.jpg.

Other applications can then request file data from the application to which the file belongs through this absolute path, so the application to which the file belongs must have access to the file itself.

That is, application A shares the relative path to application B, application B takes the relative path to find application A, and application A reads the contents of the file back to application B.

Configure FileProvider

Figure out what to do, and then what to do.

When it comes to inter-application communication, do you remember several ways of IPC?

File

AIDL

ContentProvider

Socket

Wait.

Considering ease of use, security, integrity and other aspects, Google chose ContentProvider as the solution to restrict file sharing for this application. So FileProvider was born.

The specific measures are as follows:

/ / modify the file URL acquisition method Uri photoURI = FileProvider.getUriForFile (context, context.getApplicationContext (). GetPackageName () + ".provider", createImageFile ())

After this configuration, the content:// URI can be generated, and the file contents can also be transferred to external applications through this URI.

These configuration properties of FileProvider are also common configurations of ContentProvider:

Android:name, which is the classpath of ContentProvider.

Android:authorities, which is the only label, usually package name + .provider

Android:exported, indicating whether the component can be used by other applications.

Android:grantUriPermissions, indicating whether temporary access to the authorization file is allowed.

It should be noted that android:exported should normally be true because it is intended for use by external applications.

But FileProvider is set to false here, and must be false.

This is mainly to protect the privacy of the application. If it is set to true, then any application can access the FileProvider of the current application, which is not very desirable for the application file, so the Android7.0 above will allow external applications to securely access this file in other ways, rather than the normal ContentProvider access method, which will be discussed later.

It is precisely because this attribute is true, below Android7.0, Android defaults to treating it as a normal ContentProvider, and files cannot be accessed externally through content:// URI. Therefore, it is generally necessary to judge the system version and then determine whether the incoming Uri is in File format or content format.

FileProvider source code

Then take a look at the main source code of FileProvider:

Public class FileProvider extends ContentProvider {@ Override public boolean onCreate () {return true;} @ Override public void attachInfo (@ NonNull Context context, @ NonNull ProviderInfo info) {super.attachInfo (context, info); / / Sanity check our security if (info.exported) {throw new SecurityException ("Provider must not be exported") } if (! info.grantUriPermissions) {throw new SecurityException ("Provider must grant uri permissions");} mStrategy = getPathStrategy (context, info.authority);} public static Uri getUriForFile (@ NonNull Context context, @ NonNull String authority, @ NonNull File file) {final PathStrategy strategy = getPathStrategy (context, authority); return strategy.getUriForFile (file) } @ Override public Uri insert (@ NonNull Uri uri, ContentValues values) {throw new UnsupportedOperationException ("No external inserts");} @ Override public int update (@ NonNull Uri uri, ContentValues values, @ Nullable String selection, @ Nullable String [] selectionArgs) {throw new UnsupportedOperationException ("No external updates") } @ Override public int delete (@ NonNull Uri uri, @ Nullable String selection, @ Nullable String [] selectionArgs) {/ / ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri (uri); return file.delete ()? 1: 0 } @ Override public Cursor query (@ NonNull Uri uri, @ Nullable String [] projection, @ Nullable String selection, @ Nullable String [] selectionArgs, @ Nullable String sortOrder) {/ / ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri (uri); if (projection = = null) {projection = COLUMNS } String [] cols = new String [projection.length]; Object [] values = new Object [projection.length]; int I = 0; for (String col: projection) {if (OpenableColumns.DISPLAY_NAME.equals (col)) {cols [I] = OpenableColumns.DISPLAY_NAME; values [iTunes +] = file.getName () } else if (OpenableColumns.SIZE.equals (col)) {cols [I] = OpenableColumns.SIZE; values [ionization +] = file.length ();}} cols = copyOf (cols, I); values = copyOf (values, I); final MatrixCursor cursor = new MatrixCursor (cols, 1); cursor.addRow (values) Return cursor;} @ Override public String getType (@ NonNull Uri uri) {final File file = mStrategy.getFileForUri (uri); final int lastDot = file.getName () .lastIndexOf ('.'); if (lastDot > = 0) {final String extension = file.getName () .substring (lastDot + 1); final String mime = MimeTypeMap.getSingleton () .getMimeTypeFromExtension (extension) If (mime! = null) {return mime;}} return "application/octet-stream";}}

Any ContentProvider needs to inherit the ContentProvider class and then implement these abstract methods:

OnCreate,getType,query,insert,delete,update .

(the Uri parameter in each of these methods is the content URI that we generated through the getUriForFile method.)

Let's talk about it in three parts:

Data call aspect

Among them, the four methods of query,insert,delete,update are the addition, deletion, query and modification of data, that is, the related methods of inter-process communication.

Other applications can call these methods through ContentProvider to complete the addition, deletion, query and modification of local application data, so as to complete the function of inter-process communication.

The specific method is to call the relevant methods of getContentResolver (), such as:

Cursor cursor = getContentResolver () .query (uri, null, "userid")

Go back to FileProvider:

Query, query method. In this method, the name and length of File are returned.

Insert, insert method. I didn't do anything.

Delete, delete method. Delete the File corresponding to Uri.

Update, update the method. I didn't do anything.

MIME Typ

Then look at the getType method, which mainly returns the MIME type of the data represented by Url.

The default format is generally used:

If it is a single record, return the string headed by vnd.android.cursor.item/.

If multiple records return the string headed by vnd.android.cursor.dir/

How do you use it exactly? You can match the Activity through the getType configured by the ContentProvider corresponding to the Content URI.

It's a bit of a mouthful, such as Activity and ContentProvider:

@ Override public String getType (@ NonNull Uri uri) {return "type_test";} intent.setData (mContentRUI); startActivity (intent)

After this configuration, startActivity will check whether the mineType of Activity and the getType of the corresponding ContentProvider of Content URI are the same, so that Activity can be opened normally under the same circumstances.

Initialization

Finally, take a look at the onCreate method.

In the APP startup process, all the attachInfo methods of ContentProvider are executed automatically, and finally the onCreate method is called. Generally, some initialization work is done in this method, such as initializing the database required by ContentProvider.

In FileProvider, the attachInfo method is called as an entry for initialization work, which is the same as the onCreate method, which is called when App starts.

In this method, it is also limited that the exported attribute must be false,grantUriPermissions and the attribute must be true.

If (info.exported) {throw new SecurityException ("Provider must not be exported");} if (! info.grantUriPermissions) {throw new SecurityException ("Provider must grant uri permissions");}

This initialization method and feature, which is also used by many three-party libraries, can be initialized silently without having to call the three-party library initialization method separately. For example, Facebook SDK:

Public final class FacebookInitProvider extends ContentProvider {private static final String TAG = FacebookInitProvider.class.getSimpleName (); @ Override @ SuppressWarnings ("deprecation") public boolean onCreate () {try {FacebookSdk.sdkInitialize (getContext ());} catch (Exception ex) {Log.i (TAG, "Failed to auto initialize the Facebook SDK", ex);} return false } / /...}

Once written in this way, there is no need to integrate the initialization method of FacebookSDK separately to achieve silent initialization.

The App Startup in Jetpack also takes into account the needs of these three-party libraries and merges the initialization of the three-party libraries, thus optimizing the time-consuming of creating ContentProvider multiple times.

How do I use Content URI when I get it?

Many people know how to configure FileProvider to allow others (such as photographic APP) to get our Content URI, but do you know how other people get the specific File after they get the Content URI?

In fact, if you take a closer look, you will find that there are comments in FileProvider.java:

The client app that receives the content URI can open the file and access its contents by calling {@ link android.content.ContentResolver#openFileDescriptor (Uri, String) ContentResolver.openFileDescriptor} to get a {@ link ParcelFileDescriptor}

That is, the openFileDescriptor method, which takes the ParcelFileDescriptor type data, is actually a file descriptor, and then you can read the file stream.

ParcelFileDescriptor parcelFileDescriptor = getContentResolver () .openFileDescriptor (intent.getData (), "r"); FileReader reader = new FileReader (parcelFileDescriptor.getFileDescriptor ()); BufferedReader bufferedReader = new BufferedReader (reader)

Practical application of ContentProvider

In the usual work, there are mainly the following situations that deal with ContentProvider more often:

Communicate with some App of the system, such as getting the address book, calling to take pictures, etc. The same is true of the above-mentioned FileProvider.

Have some interaction with your own APP. For example, between your own multi-applications, you can exchange some data through this.

The initialization of the three-party library. Many third-party libraries take advantage of the automatic initialization of ContentProvider to do a silent, unaware initialization.

At this point, I believe you have a deeper understanding of "how to understand ContentProvider through FileProvider". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report