10

別のアプリ(アプリB)からカスタムコンテンツプロバイダー(アプリA)をクエリしようとしています。

コンテンツプロバイダーの権限保護がない場合にそれを行うことができます。具体的には、アプリAでカスタムコンテンツプロバイダーを構築し、URIを含むインテントをアプリBに送信しました。これがアプリAのインテント送信部分です。

class InsertOnClickListener implements OnClickListener{        
        public void onClick(View v) {
            ContentValues values = new ContentValues();
            values.put(DataBaseConfiguation.TableConfiguation.USER_NAME, "Jack");
            Uri uri = getContentResolver().insert(DataBaseConfiguation.TableConfiguation.CONTENT_URI, values);
            System.out.println("uri------------------->" + uri);
            // the uri above should be like "content://com.catking.contentprovider.MyContentProvider/user"
            Uri uri2 = Uri.parse("content://com.catking.contentprovider.MyContentProvider/user");
              Cursor c = managedQuery(uri2, null, null, null, null);
              String sendvalue = null;
               if (c.moveToFirst()) {
                  do{
                     System.out.println("User name:"+c.getString(c.getColumnIndex(DataBaseConfiguation.TableConfiguation.USER_NAME)).toString());               
                     sendvalue = c.getString(c.getColumnIndex(DataBaseConfiguation.TableConfiguation.USER_NAME)).toString();
                  } while (c.moveToNext());
               }
            Intent sendIntent = new Intent();
            sendIntent.setClassName("com.android.web", "com.android.web.Provid");
            sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            sendIntent.putExtra("name", uri2.toString());
            sendIntent.setType("text/plain");
            startActivity(sendIntent);
        }
}

続いてアプリAのマニフェストファイル。

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name=".ContentProviderTestActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <provider android:authorities="com.catking.contentprovider.MyContentProvider"
        android:exported="true"
        android:grantUriPermissions="true"
        android:name="com.catking.contentprovider.MyContentProvider" 
        android:readPermission="android.permission.permRead"
        android:writePermission="android.permission.permWrite" >
    </provider>
</application>

次に、アプリB(クラスProvid)がURIを取得し、コンテンツプロバイダーで対応するデータをクエリします(次のコードを使用)。

public class Provid extends Activity {

public void onCreate(Bundle savedInstanceState) {
    Bundle extras = getIntent().getExtras(); 
    String userNameuri;
    if (extras != null) {
        userNameuri = extras.getString("name");
      Uri allTitles = Uri.parse(userNameuri);
      Cursor c = managedQuery(allTitles, null, null, null, null);
       if (c.moveToFirst()) {
          do{
             System.out.println("Name is"+c.getString(c.getColumnIndex(DataBaseConfiguation.TableConfiguation.USER_NAME)).toString());               
          } while (c.moveToNext());
       }
    }
}

}

これがアプリBのマニフェストファイルです。

<uses-permission android:name="android.permission.INTERNET" />
<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name="._GetWebResoureActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.SEND" >
            </action>
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="*/*" />
        </intent-filter>
    </activity>

    <receiver android:name="StaticReceiver11" >
        <intent-filter>
            <action android:name="android.intent.action.MYSEND" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

    <activity
        android:name="Provid"
        android:label="@string/title_activity_provid" >
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="*/*" />
        </intent-filter>

    </activity>
</application>

ただし、アプリBからコンテンツプロバイダーにクエリを実行すると、エラーが発生します。

java.lang.RuntimeException: Unable to start activity ComponentInfo {com.android.web/com.android.web.Provid}: java.lang.SecurityException: Permission Denial: opening     provider com.ck.contentprovider.MyContentProvider from ProcessRecord{426c6ea8 17032:com.android.web/u0a95} (pid=17032, uid=10095) requires android.permission.permRead or android.permission.permWrite   

アプリBは一時的なアクセス許可を利用していなかったようです。言い換えれば、アプリBからFLAG_GRANT_READ_URI_PERMISSIONを利用するにはどうすればよいですか?

また、Uri.toString()(putExtra()を使用)の代わりに、(setData()を使用して)intentにUriを直接追加しようとしました。

sendIntent.setData(uri2);

Uri userNameuri = getIntent().getData(); 

ただし、アプリBで取得した「userNameuri」はnullです。

私は完全に混乱しています...

更新しました

以前の投稿によると、「grantUriPermission( "com.android.getCPaccess"、uri2、Intent.FLAG_GRANT_READ_URI_PERMISSION)」を試しました。
機密性の高いアプリデータをメールの添付ファイルとして送信する場合の正しい権限処理は何ですか?

そしてそれは確かに機能します。FLAG_GRANT_READ_URI_PERMISSIONを使用しなくても機能します。しかし、許可は「一時的」ではありません。revokeUriPermission()を使用して手動で終了する必要があります。

それで、FLAG_GRANT_READ_URI_PERMISSIONで導入されたような一時的な許可を与える方法があるのか​​、それともバグなのか疑問に思います。

4

1 に答える 1

12

エクストラのURIにFLAG_GRANT_READ_URI_PERMISSIONのみ影響するようですが、影響はありません。Uri Intent.mData

で遊んでいるときに同様の問題が見つかりました。ACTION_SENDこれにはURIが必要EXTRA_STREAMです。同じURIを提供することsetData()は機能しますが、ルールに準拠しておらず、予期しない動作(Gmail受信者など)につながります。

Jelly Beanの時点では、インテントにClipDataを含めることができます。これにより、問題が解決するはずです。それACTION_SENDはエクストラから自動的に生成されるからです。

grantUriPermission動作しますが、が必要revokeUriPermissionです。startActivity(Intent.createChooser(intent, title))ターゲット()を選択する必要があるのと同じ仕事をするにはACTION_PICK_ACTIVITY、そのパッケージにアクセス許可を付与し、不要になったときにそれらを取り消します(onActivityResult?)。

ここにいくつかのコードがあります:

レシーバーアプリ:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.handler" >

    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        …
        <activity
            android:name=".ActivityView"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="android.intent.action.SEND"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="*/*"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

ActivityView.java:

protected void onCreate(Bundle savedInstanceState) {
    Intent intent = getIntent();
    if ((intent != null)) {
        procUri(intent.getData());
        procUri(intent.<Uri>getParcelableExtra(Intent.EXTRA_STREAM));
    }
}

private void procUri(Uri uri) {
    if (uri != null) {
        InputStream i;
        try {
            i = getContentResolver().openInputStream(uri);
            byte[] b = new byte[i.available()];
            i.read(b);
            …
        } catch (Throwable e) {
            …
        }
    }
}

送信者アプリ:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sender" >

    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        …
        <activity
            android:name=".ActivitySend"
            android:label="@string/app_name" >
        </activity>
        <provider
            android:name=".MyContentProvider"
            android:authorities="com.example.sender.content"
            android:enabled="true"
            android:exported="false"
            android:grantUriPermissions="true" >
        </provider>
    </application>
</manifest>

ActivitySend.java:

// OK!
private void doTestView(Uri uri, String type) {
    startActivity(
            new Intent(Intent.ACTION_VIEW)
                .setDataAndType(uri, type)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        );
}

// error prior to JellyBean
// ok on JellyBean, even without explicit FLAG_GRANT_READ_URI_PERMISSION (due to generated ClipData)
private void doTestSend(Uri uri, String type, CharSequence title) {
    startActivity(
            Intent.createChooser(
                new Intent(Intent.ACTION_SEND)
                    .setType(type)
                    .putExtra(Intent.EXTRA_STREAM, uri)
                    .putExtra(Intent.EXTRA_SUBJECT, title)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                ,
                title
            )
        );
}

// working but not ok, unexpected results!
private void doTestSend2(Uri uri, String type, CharSequence title) {
    startActivity(
            Intent.createChooser(
                new Intent(Intent.ACTION_SEND)
                    .setDataAndType(uri, type)
                    .putExtra(Intent.EXTRA_STREAM, uri)
                    .putExtra(Intent.EXTRA_SUBJECT, title)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                ,
                title
            )
        );
}
于 2013-02-15T14:10:46.810 に答える