Android 11の新機能、スコープストレージには新しいトリックがあります

この記事は、私のWeChat公式アカウントで同時に公開されています。記事の下部にあるQRコードをスキャンするか、WeChatでGuo Linを検索して、フォローしてください。記事は毎日更新されます。

Android 11が正式にリリースされてから半年以上が経ちました。Android11の新機能に関する記事を書く時が来ました。

最初は、Android 11での動作の変更について知ったと思います。一般的には多くの変更がありますが、適応が必要な場所は多くありません。適応が必要な領域の1つは、Android 11の権限の変更です。コンテンツのこの部分に関して、PermissionXでJavaサポートするようになりましたAndroid 11の権限変更の説明もあります。この記事では、すでに詳細な説明を行っています。

さらに、スコープストレージでは、Android 11にいくつかの新しい変更が加えられています。この記事では、この部分に焦点を当てます。

スコープストレージ

実際、スコープストレージはAndroid 11でリリースされた新機能ではありませんが、Android 10にはすでに存在します。また、当時この機能を説明する記事も書きました。Android10の適応ポイントとスコープを参照できます。ストレージ

心配しないでください。前の記事で説明した内容は古くなっていません。当時Android10で利用可能だった機能は、Android 11でも引き続き利用できますが、Android11ではスコープストレージが強化および拡張されています。したがって、これが私たちの記事の焦点であることは間違いありません。

スコープストレージを強制的に有効にする

まず、Android 11では、スコープストレージが強制的に有効になっています。

それで、それを強制することはどういう意味ですか?

Android 10にはスコープストレージ機能もありますが、Googleは幅広いアプリケーションに適応するには時間がかかると考えているため、この機能は必須ではありません。

アプリケーションによって指定されたtargetSdkVersionが29未満であるか、targetSdkVersionが29に等しい限り、次の構成がAndroidManifest.xmlに追加されます。

<manifest ... >
  <application android:requestLegacyExternalStorage="true" ...>
    ...
  </application>
</manifest>

その場合、スコープストレージ機能は有効になりません。

上記の構成はAndroid11でも引き続き有効ですが、targetSdkVersionが29以下の場合に限ります。targetSdkVersionが30に等しい場合、スコープストレージが強制的に有効になり、requestLegacyExternalStorageフラグは無視されます。

では、スコープストレージを有効にした後、開発者に影響はありますか?

実際、この記事で説明されている方法でアプリケーションがスコープストレージに適応されている場合は、Android 10の適応ポイントであるスコープストレージに従って、おめでとうございます。何もする必要はありません。すでにAndroidに適応できます。 11システム。

つまり、ほとんどの開発者にとって、アプリケーションが以前にAndroid 10スコープストレージに適合されている限り、スコープストレージを強制的に有効にしても効果はありません。

しかし、非常に特殊なタイプのアプリケーション、つまり、Root Explorer、ESExplorerなどのファイルブラウザがあります。この種のプログラム自体が提供する機能は、SD上のファイルを参照および管理することであり、スコープストレージを強制的に有効にすると、ファイル参照の概念は本質的になくなり、実際のパスでファイルを管理できなくなります。

この観点から、スコープストレージはファイルブラウザプログラムに壊滅的な打撃を与えました。しかし、心配しないでください、グーグルはまだこの種のプログラムのための別の解決策を提供します、それについて以下で学びましょう。

デバイス上のすべてのファイルを管理する

まず、Android 11でスコープストレージを有効にすることは、ユーザーのプライバシーをより適切に保護し、より安全なデータ保護を提供することであることを明確にします。ほとんどのアプリケーションでは、MediaStoreが提供するAPIはすでに開発ニーズを満たすことができます。ファイルブラウザの開発と同様の要件がない場合は、次に紹介するテクノロジを使用しないようにしてください。

SDカード全体の読み取りおよび書き込み権限を持つことは、Android 11では非常に危険な権限と見なされます。これは、ユーザーのデータセキュリティにも大きな影響を与える可能性があります。

しかし、ファイルブラウザはデバイスのSDカード全体を管理するためのものです。どうすればよいですか?このような非常に危険な権限の場合、Googleは通常、インテントを使用して特別な承認ページにジャンプし、フローティングウィンドウ、ユーザー補助サービスなど、ユーザーが手動で承認できるようにガイドします。

はい、Android 11では、デバイス全体でファイルを管理する場合も、同様の手法を使用する必要があります。

まず、以下に示すように、AndroidManifest.xmlでMANAGE_EXTERNAL_STORAGE権限を宣言する必要があります。

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

    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />

</manifest>

従来の権限の宣言と比較して、tools:ignore = "ScopedStorage"などの属性がここに追加されていることに注意してください。この属性を追加しない場合、Android Studioは、前に紹介したように、ほとんどのアプリケーションがこの権限を申請するべきではないという警告を表示するためです。

次の作業も非常に簡単です。アクションACTION_MANAGE_ALL_FILES_ACCESS_PERMISSIONを使用して、指定した承認ページにジャンプできます。Environment.isExternalStorageManager()関数を使用して、ユーザーが承認されているかどうかを判断できます。以下に、これを示す比較的簡単なコードを記述します。関数:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R ||
        Environment.isExternalStorageManager()) {
    
    
    Toast.makeText(this, "已获得访问所有文件权限", Toast.LENGTH_SHORT).show()
} else {
    
    
    val builder = AlertDialog.Builder(this)
        .setMessage("本程序需要您同意允许访问所有文件权限")
        .setPositiveButton("确定") {
    
     _, _ ->
            val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
            startActivity(intent)
        }
    builder.show()
}

システムバージョンがAndroid11よりも低い場合、またはEnvironment.isExternalStorageManager()がtrueを返す場合は、SDカード全体を管理する権限がすでにあることを意味していることがわかります。これで、従来の書き込み方法を直接使用して、実際のパスの形式でファイルを操作できます。

また、SDカードを管理する権限がない場合は、ダイアログボックスが表示され、権限を申請する理由がユーザーに通知されます。次に、インテントを使用して指定された認証ページにジャンプし、ユーザーが手動で認証できるようにします。

プログラムの実行効果を次の図に示します。

この許可があれば、過去に知っていた方法でファイルブラウザを開発できます。

ただし、もう1つ注意すべき点があります。SDカードを管理する権限があっても、Androidディレクトリ内の多くのリソースは制限されています。たとえば、Android11ではAndroid / dataディレクトリにアクセスできません。多くのアプリケーションのデータ情報はこのディレクトリに保存されるため、この制限の目的は主にユーザーのデータセキュリティを考慮することです。そうでなければ、WeChatに淘宝網のデータの読み取りを許可することは不適切と思われます。

バッチ操作

Android11のスコープストレージのもう1つの新機能を見てみましょう。

スコープストレージは、携帯電話のアルバムに画像を挿入するなど、各アプリケーションがMediaStoreにデータを提供する権利を有することを規定しています。また、電話のアルバム内のすべての写真を取得するなど、他のアプリケーションによって提供されたデータを読み取る権限もあります。これらの機能は、Android10アダプテーションポイントとスコープストレージに関するこの記事で説明されています。

ただし、他のアプリケーションによって提供されたデータを変更する場合は、申し訳ありませんが、スコープストレージでは変更できません。

理由も非常に単純です。電話のアルバムに写真を挿入する場合、あなたは確かにそれを任意に変更する権限を持っています。ただし、この画像が別のアプリケーションによって電話アルバムに挿入された場合は、任意に変更できます。これは、Googleの見解では別のセキュリティリスクであるため、スコープストレージはこの機能を制限します。

ただし、一部のアプリケーションが他のアプリケーションによって提供されたデータを変更する必要がある場合はどうなりますか?Photoshop、Meitu Xiuxiuなど、そのような例を見つけるのは難しくありません。それらの目的は、写真が自分で作成されているかどうかに関係なく、携帯電話のアルバムの写真を変更することです。

この問題を解決するために、Android10は解決策を提供します。

try {
    
    
    contentResolver.openFileDescriptor(imageContentUri, "w")?.use {
    
    
        Toast.makeText(this, "现在可以修改图片的灰度了", Toast.LENGTH_SHORT).show()
    }
} catch (securityException: SecurityException) {
    
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    
    
        val recoverableSecurityException = securityException as?
            RecoverableSecurityException ?:
            throw RuntimeException(securityException.message, securityException)

        val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender
        intentSender?.let {
    
    
            startIntentSenderForResult(intentSender, IMAGE_REQUEST_CODE,
                    null, 0, 0, 0, null)
        }
    } else {
    
    
        throw RuntimeException(securityException.message, securityException)
    }
}

このコードについて簡単に説明します。

まず、このコードの目的は画像のグレースケールを変更することですが、この画像は現在のアプリケーションによって提供されていないため、理論的には現在のアプリケーションにはこの画像のグレースケールを変更する権限がありません。

したがって、明らかに変更する権限がありませんが、変更を主張するとどうなりますか?これは理解しやすく、もちろん例外がスローされます。したがって、これは、画像のグレースケール操作をラップし、catchコードブロックで現在のシステムバージョンがAndroid 10以上であり、例外のタイプがRecoverableSecurityExceptionであるかどうかを判断する、trycatchメソッドです。スコープストレージ制限が原因で、許可なく異常な操作が発生します。

次に、RecoverableSecurityExceptionオブジェクトからintentSenderを取得し、このintentSenderを使用してページにジャンプし、この画像を変更する権限を手動で付与するようにユーザーをガイドします。動作効果は以下のとおりです。

この方法は実行可能ですが、非常に明らかな欠点があります。一度に1つの画像しか操作できないということです。プログラムが多くの写真を変更する必要がある場合、良い方法はありません。上記の方法でのみ、各写真の許可を申請できます。

Googleもこの問題を認識していると思うので、Android 11にバッチ操作と呼ばれる新機能を導入しました。これにより、一度に複数のファイル操作権限を申請できます。

バッチ操作の使用法もよく理解されています。Googleは、以下に示すように、合計4種類の権限アプリケーションAPIを提供しています。

  • createWriteRequest()は、複数のファイルへの書き込み権限を要求するために使用されます。
  • createFavoriteRequest()は、複数のファイルをお気に入りに追加する権限を要求するために使用されます。
  • createTrashRequest()は、複数のファイルをごみ箱に移動する許可を要求するために使用されます。
  • createDeleteRequest()は、複数のファイルを削除する権限を要求するために使用されます。

最も一般的に使用される2つのインターフェースは、createWriteRequest()とcreateDeleteRequest()です。ここでは、例としてcreateWriteRequest()を取り上げます。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    
    
    val urisToModify = listOf(uri1, uri2, uri3, uri4)
    val editPendingIntent = MediaStore.createWriteRequest(contentResolver, urisToModify)
    startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
            null, 0, 0, 0)
}

コードは非常に単純です。まず、アクセス許可に適用するすべてのファイルUrisをバッチで格納するコレクションを作成し、次にcreateWriteRequest()関数を呼び出してPendingIntentを作成し、次にstartIntentSenderForResultを呼び出してアクセス許可を適用します。

許可申請の結果については、onActivityResult()で監視できます。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    
    
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
    
    
        EDIT_REQUEST_CODE -> {
    
    
            if (resultCode == Activity.RESULT_OK) {
    
    
                Toast.makeText(this, "用户已授权", Toast.LENGTH_SHORT).show()
            } else {
    
    
                Toast.makeText(this, "用户没有授权", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

プログラムの実行結果を次の図に示します。

他のいくつかのAPIの使用法はまったく同じなので、ここでは例を繰り返しません。

これを見て、Android10とAndroid11が提供するAPIは完全に異なると言う友人もいるかもしれません。Android10は例外キャプチャメカニズムに依存してRecoverableSecurityExceptionからintentSenderを解析しますが、Android11はバッチ操作によって提供されるAPIを直接使用できます。作成intentSender。適応するには、プロジェクトでAndroid10とAndroid11の2セットのコードを記述する必要がありますか?

これは確かに頭痛の種であり、主にAndroid10でのGoogleの不合理なAPI設計が原因だと思います。例外キャッチメカニズムに依存するスキームは、いずれの場合も優れたAPI設計とは言えません。

しかし、後でもっと考えてみると、これは解決できない問題ではなく、解決策はまだ非常に簡単であることがわかりました。

どうして?Android 10のスコープストレージを有効にする必要はありません。AndroidManifest.xmlでrequestLegacyExternalStorageフラグを構成して、スコープストレージを無効にすることができます。この場合、Android 10は適応を必要としません。スコープストレージの適応には、Android11でより科学的で標準化されたAPIを使用するだけで済みます。

さて、この記事はここで終わります。記事のすべてのコード例をデモとして記述し、GitHubに配置しました。困っている友人は、次のWebサイトで確認できます。

https://github.com/guolindev/ScopedStorageDemo

さらに、Kotlinと最新のAndroidの知識を学びたい場合は、私の新しい本「First Line of Code 3rd Edition」を参照できます。詳細についてはここをクリックしてください


私のテクニカルパブリックアカウントに注意を払い、毎日高品質のテクニカル記事をプッシュしてください。

以下のQRコードをWeChatでスキャンしてフォローしてください。

おすすめ

転載: blog.csdn.net/sinyu890807/article/details/113954552