قبل التغييرات الجديدة على نظام Android مع الإصدار 11 ، كان طلب الإذن لكل من الخلفية(Background) والمقدمة(Foreground) لحالات التطبيق هو نفس الشيئ ، فقط اطلب إذنًا واحدًا وكان كل شيء بسيطًا وسهلاً ، ولكن ليس بعد الآن.
بضفه عامة هنالك نوعان من الوصول للموقع:
- صلاحية الوصول من الخلفية Background location
-
صلاحية الوصول من المقدمة Foreground location
التغييرات الجديدة
بدءًا من Android 11
لكي يتلقى تطبيقك موقع الخلفية ، يجب عليك طلب إذن جديد ACCESS_BACKGROUND_LOCATION
مباشرة بعد أن تطلب الأذونات العادية ACCESS_COARSE_LOCATION
أو ACCESS_FINE_LOCATION
أو كليهما وسيستمر كل شيء في العمل كما كان من قبل.
تذكر اذا لم تقم بطلب هذه الصلاحيات بالطريقة المذكورة اعلاه فلن يكون هنالك استجابة مثل ان تطلب صلاحية ACCESS_BACKGROUND_LOCATION
قبل ACCESS_COARSE_LOCATION
أو ACCESS_FINE_LOCATION
متى يجب أن تطلب هذا الإذن؟
بشكل عام عند وجود أي ميزة في التطبيق تتطلب الوصول إلى الموقع أثناء التواجد في الخلفية ، فإليك بعض حالات الاستخدام التي صادفتها أثناء العمل:
- عندما تريد تشغيل Foreground service من الخلفية كمثال
عندما تريد تشغيل تتبع الموقع في الخليفة عندي يتنهي الهاتف من اعادة تشغيل الجهاز (booting) فعندها يجب عليك طلب هذه الصلاحية
- الوظائف المجدولة التي تستخدم الموقع (
WorkManager
،AlarmManager
.. إلخ).
مثال:
سيكون لدينا تطبيق بسيط يحتوي على زر واحد ، وسيطلب إذنًا عاديًا (ACCESS_COARSE_LOCATION
، ACCESS_FINE_LOCATION
) و ACCESS_BACKGROUND_LOCATION
على التوالي
هيا لنبدأ
ابدأ أولاً بإضافة الأذونات في ملف AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.m7mdra.backgroundlocationpermissiondemo">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<application
...
الان لنقم بطلب الصلاحية
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<MaterialButton>(R.id.permissionButton)
button.setOnClickListener {
checkLocationPermission()
}
}
وهنا حيث يحدث كل شيئ
private fun checkLocationPermission() {
//تحقق اذا لم يتم منح صلاحية الوصول للموقع
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
//ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION طلب الصلاحية للموقع
requestPermissionOrShowRational(13)
} else {
// تحقق من نسخة نظام التشغيل , نسخة تساوي ١١ او اعلى
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//ACCESS_BACKGROUND_LOCATION تحقق من صلاحية الوصول للموقع في الخلفية
if (hasBackgroundPermission()) {
// تم منح الصلاحية مسبقا
Toast.makeText(this," تم منح الصلاحية في الخلفية",Toast.LENGTH_SHORT).show()
} else {
//ACCESS_BACKGROUND_LOCATION طلب الصلاحية
showBackgroundLocationDialog(13)
}
} else {
// تم منح الصلاحية مسبقا
Toast.makeText(this,"تم منح الصلاحية",Toast.LENGTH_SHORT).show()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode == 13){
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"تم منح الصلاحية",Toast.LENGTH_SHORT).show()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//الان لنقم بطلب صلاحية الموقع من الخلفية
showBackgroundLocationDialog(14)
}else {
Toast.makeText(this,"تم منح الصلاحية في الخلفية مسبقاً",Toast.LENGTH_SHORT).show()
}
}else{
//اظهار رسالة تبين رفض الصلاحية
showPermissionDeniedDialog()
}
}
if(requestCode == 14){
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"تم منح الصلاحية في الخلفية ",Toast.LENGTH_SHORT).show()
}else{
//اظهار رسالة تبين رفض الصلاحية
showPermissionDeniedDialog()
}
}
}
وهذا كل شيء ، والآن سنقوم بتشغيل تطبيقنا ومعرفة ما إذا كان يعمل
صور
1 | 2 | 3 | 4 |
---|---|---|---|
السورس كود متوفر هنا
النهاية