يمكنك الحصول على إحصاءات عن كيفية وصول تطبيقك ومستلزماته إلى البيانات الخاصة
من المستخدمين من خلال إجراء تدقيق في الوصول إلى البيانات. تتوفّر هذه العملية على
الأجهزة التي تعمل بالإصدار 11 (المستوى 30 لواجهة برمجة التطبيقات) من نظام Android والإصدارات الأحدث، وتتيح لك معرفة
بشكل أفضل حالات الوصول إلى البيانات غير المتوقّعة. يمكن لتطبيقك تسجيل مثيل
من AppOpsManager.OnOpNotedCallback
، والذي يمكنه تنفيذ
إجراءات في كل مرة يحدث فيها أحد الأحداث التالية:
- رمز تطبيقك يصل إلى البيانات الخاصة. لمساعدتك في تحديد الجزء المنطقي من تطبيقك الذي استدعى الحدث، يمكنك تدقيق الوصول إلى البيانات حسب علامة تحديد المصدر.
- الوصول إلى البيانات الخاصة من خلال رمز في مكتبة أو حزمة تطوير برامج (SDK) معتمِدة
يتمّ تفعيل ميزة "التدقيق في الوصول إلى البيانات" في سلسلة المحادثات التي يتمّ فيها تنفيذ طلب البيانات. وهذا يعني أنّه إذا كانت حزمة SDK أو مكتبة تابعة لجهة خارجية في تطبيقك تستدعي واجهة برمجة تطبيقات
تتمكّن من الوصول إلى البيانات الخاصة، تسمح لك ميزة "تدقيق الوصول إلى البيانات" في
OnOpNotedCallback
بفحص معلومات عن الطلب. يمكن أن يحدِّد عنصر callback عادةً ما إذا كانت المكالمة واردة من تطبيقك أو من حزمة SDK من خلال النظر في الحالة الحالية للتطبيق، مثل تتبُّع تسلسل استدعاء الدوال البرمجية للسلسلة الحالية.
تسجيل الوصول إلى البيانات
لإجراء تدقيق في الوصول إلى البيانات باستخدام مثيل
AppOpsManager.OnOpNotedCallback
، نفِّذ منطق الاستدعاء في المكوّن
الذي تريد تدقيق الوصول إلى البيانات فيه، مثل ضمن onCreate()
طريقة النشاط أو onCreate()
طريقة التطبيق.
يحدد مقتطف الرمز التالي AppOpsManager.OnOpNotedCallback
لتدقيق الوصول إلى البيانات في نشاط واحد:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() { private fun logPrivateDataAccess(opCode: String, trace: String) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\nStack Trace:\n$trace") } override fun onNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess( syncNotedAppOp.op, Throwable().stackTrace.toString()) } override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess( syncNotedAppOp.op, Throwable().stackTrace.toString()) } override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.message) } } val appOpsManager = getSystemService(AppOpsManager::class.java) as AppOpsManager appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback) }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { AppOpsManager.OnOpNotedCallback appOpsCallback = new AppOpsManager.OnOpNotedCallback() { private void logPrivateDataAccess(String opCode, String trace) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\nStack Trace:\n$trace"); } @Override public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.getOp(), asyncNotedAppOp.getMessage()); } }; AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); if (appOpsManager != null) { appOpsManager.setOnOpNotedCallback(getMainExecutor(), appOpsCallback); } }
يتمّ استدعاء الطريقتَين onAsyncNoted()
وonSelfNoted()
في حالات
معيّنة:
يتمّ استدعاء
onAsyncNoted()
في حال عدم الوصول إلى البيانات أثناء معالجة طلب بيانات تطبيقك من واجهة برمجة التطبيقات. وأكثر الأمثلة شيوعًا هو عندما يسجِّل تطبيقك مستمعًا ويتم الوصول إلى البيانات في كل مرة يتم فيها استدعاء طلب الاستدعاء للمستمع.تحتوي الوسيطة
AsyncNotedOp
التي تم تمريرها إلىonAsyncNoted()
على طريقة تُسمىgetMessage()
. تقدّم هذه الطريقة مزيدًا من المعلومات حول إمكانية الوصول إلى البيانات. في حال تلقّي مكالمات استرجع البيانات المتعلّقة بالموقع الجغرافي، تحتوي الرسالة على مفتاح تجزئة نظام الهوية للمستمع.يتمّ استدعاء
onSelfNoted()
في الحالة النادرة جدًا عندما يُرسِل تطبيق معيّن معرّف مستخدم فريدًا خاصًا به إلىnoteOp()
.
تدقيق الوصول إلى البيانات حسب علامة تحديد المصدر
قد يكون لتطبيقك عدة حالات استخدام أساسية، مثل السماح للمستخدمين بالتقاط
الصور ومشاركتها مع جهات اتصالهم. إذا كنت تطوّر
تطبيقًا متعدد الأغراض، يمكنك تطبيق علامة تحديد المصدر على كل جزء من تطبيقك
عند تدقيق الوصول إلى بياناته. يتمّ إرجاع سياق attributionTag
مجددًا
في الكائنات التي تمّ تمريرها إلى طلبات onNoted()
.
يساعدك ذلك في تتبُّع الوصول إلى البيانات بسهولة أكبر إلى الأجزاء المنطقية من
الرمز البرمجي.
لتحديد علامات الإسناد في تطبيقك، أكمِل الخطوات الواردة في القسمين التاليين:
إدراج علامات تحديد المصدر في البيان
إذا كان تطبيقك يستهدف الإصدار 12 من Android (المستوى 31 من واجهة برمجة التطبيقات) أو إصدارًا أحدث، عليك الإفصاح عن
علامات الإسناد في ملف بيان تطبيقك باستخدام التنسيق الموضَّح في ملف
اقتباس الرمز البرمجي التالي. إذا حاولت استخدام علامة تحديد مصدر لم يتم
الإفصاح عنها في ملف بيان تطبيقك، سينشئ النظام علامة null
نيابةً عنك ويتسجيل
رسالة في Logcat.
<manifest ...> <!-- The value of "android:tag" must be a literal string, and the value of "android:label" must be a resource. The value of "android:label" is user-readable. --> <attribution android:tag="sharePhotos" android:label="@string/share_photos_attribution_label" /> ... </manifest>
إنشاء علامات الإسناد
في طريقة
onCreate()
في النشاط الذي تصل من خلاله إلى البيانات، مثل النشاط الذي
تطلب فيه الموقع الجغرافي أو الوصول إلى قائمة جهات اتصال المستخدِم، أو استدعاء
createAttributionContext()
،
مع تمرير علامة تحديد المصدر التي تريد ربطها بجزء من تطبيقك.
يوضح مقتطف الرمز التالي كيفية إنشاء علامة إحالة لجزء مشاركة موقع صورة من أحد التطبيقات:
Kotlin
class SharePhotoLocationActivity : AppCompatActivity() { lateinit var attributionContext: Context override fun onCreate(savedInstanceState: Bundle?) { attributionContext = createAttributionContext("sharePhotos") } fun getLocation() { val locationManager = attributionContext.getSystemService( LocationManager::class.java) as LocationManager // Use "locationManager" to access device location information. } }
Java
public class SharePhotoLocationActivity extends AppCompatActivity { private Context attributionContext; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { attributionContext = createAttributionContext("sharePhotos"); } public void getLocation() { LocationManager locationManager = attributionContext.getSystemService(LocationManager.class); if (locationManager != null) { // Use "locationManager" to access device location information. } } }
تضمين علامات الإسناد في سجلّات الوصول
عدِّل رد استدعاء "AppOpsManager.OnOpNotedCallback
" بحيث تتضمّن سجلّات تطبيقك أسماء علامات تحديد المصدر التي حدّدتها.
يعرض مقتطف الرمز التالي المنطق المعدَّل الذي يسجّل علامات الإسناد:
Kotlin
val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() { private fun logPrivateDataAccess( opCode: String, attributionTag: String, trace: String) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\n " + "Attribution Tag:$attributionTag\nStack Trace:\n$trace") } override fun onNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.op, syncNotedAppOp.attributionTag, Throwable().stackTrace.toString()) } override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.op, syncNotedAppOp.attributionTag, Throwable().stackTrace.toString()) } override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.attributionTag, asyncNotedAppOp.message) } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { AppOpsManager.OnOpNotedCallback appOpsCallback = new AppOpsManager.OnOpNotedCallback() { private void logPrivateDataAccess(String opCode, String attributionTag, String trace) { Log.i("MY_APP_TAG", "Private data accessed. " + "Operation: $opCode\n " + "Attribution Tag:$attributionTag\nStack Trace:\n$trace"); } @Override public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), syncNotedAppOp.getAttributionTag(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), syncNotedAppOp.getAttributionTag(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.getOp(), asyncNotedAppOp.getAttributionTag(), asyncNotedAppOp.getMessage()); } }; AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); if (appOpsManager != null) { appOpsManager.setNotedAppOpsCollector(appOpsCollector); } }