Irbisa · Шпаргалка
Разрешения и приватность
Runtime-разрешения, purpose strings, ATT, геолокация, фото, privacy manifest, согласия, аудит SDK
Чем запрос разрешения на Android отличается от iOS?
Что означают варианты «Только в этот раз» и «Приблизительное» в диалоге разрешений Android для вашего кода?
Онбординг на первом экране просит геолокацию, контакты и уведомления, и большинство пользователей отказывает во всех трёх. Когда спрашивать правильно?
@Composablefun AddToCalendarButton(vm: BookingViewModel) { val context = LocalContext.current var showPrimer by remember { mutableStateOf(false) } val launcher = rememberLauncherForActivityResult( ActivityResultContracts.RequestPermission()…Приложение падает, когда пользователь нажимает «Сканировать». Что не так с этим запросом разрешения?
class ScanFragment : Fragment(R.layout.fragment_scan) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { view.findViewById<Button>(R.id.scan).setOnClickListener { val request = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> if (granted) startScanner() } request.launch(Manifest.permission.CAMERA) } }}shouldShowRequestPermissionRationaleвозвращаетfalseи на свежей установке, и после того, как пользователь заблокировал разрешение. Как различить эти состояния?class PermissionGate(private val prefs: DataStore<Preferences>) { private fun blockedKey(permission: String) = booleanPreferencesKey("blocked_$permission") suspend fun state(activity: Activity, permission: String): PermissionState = when { ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED -> PermissionState.Granted…Какие фичи можно сделать вообще без запроса dangerous-разрешения, переложив работу на системный компонент?
// Photo: the camera app takes it and writes to your FileProvider Uri. No CAMERA permission.private val takePhoto = registerForActivityResult(ActivityResultContracts.TakePicture()) { saved -> if (saved) upload(photoUri)}// takePhoto.launch(photoUri)…Что такое Photo Picker и частичный доступ к медиа в Android 14 и почему пикер лучше, чем
READ_MEDIA_IMAGES?// Attaching an avatar: no permission, no manifest entry, nothing to denyval pickAvatar = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> if (uri != null) upload(uri)}fun chooseAvatar() = pickAvatar.launch( PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)…Найдите баг: выбранная аватарка отображается, но после перезапуска приложения она пропадает, а в логе исключение.
class ProfileFragment : Fragment(R.layout.fragment_profile) { private val prefs by lazy { requireContext().getSharedPreferences("profile", Context.MODE_PRIVATE) } private val pickAvatar = registerForActivityResult(PickVisualMedia()) { uri -> if (uri == null) return@registerForActivityResult prefs.edit { putString("avatar_uri", uri.toString()) } showAvatar(uri) // reads it with contentResolver.openInputStream(uri) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { prefs.getString("avatar_uri", null)?.let { showAvatar(it.toUri()) } view.findViewById<Button>(R.id.change_avatar).setOnClickListener { pickAvatar.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly)) } }}Приложению курьера нужна геолокация водителя при выключенном экране во время доставки. Какие разрешения запрашивать и нужна ли фоновая геолокация вообще?
private val requestLocation = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions()) { result -> when { result[Manifest.permission.ACCESS_FINE_LOCATION] == true -> startTrip(precise = true) result[Manifest.permission.ACCESS_COARSE_LOCATION] == true -> startTrip(precise = false)…После повышения
targetSdkэтот код всегда показывает «No maps app installed», хотя Google Maps на телефоне стоит. Почему и как исправить?fun openInMaps(context: Context, lat: Double, lng: Double) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse("geo:$lat,$lng")) if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { Toast.makeText(context, "No maps app installed", Toast.LENGTH_SHORT).show() }}Что меняют для приложения индикаторы и переключатели камеры и микрофона в Android 12?
Минорное обновление SDK добавило
READ_PHONE_STATEв ваш релизный манифест. Как найти, откуда оно взялось, и какие есть варианты?// build.gradle.kts (:app): run ./gradlew checkReleasePermissions in CI// import com.android.build.api.artifact.SingleArtifactabstract class CheckPermissions : DefaultTask() { @get:InputFile abstract val mergedManifest: RegularFileProperty @get:InputFile abstract val allowList: RegularFileProperty…Что требует форма Data safety в Play и как на ответы влияют сторонние SDK?
Что такое App Tracking Transparency и что происходит с IDFA и атрибуцией рекламы, когда пользователь отказывает?
import AppTrackingTransparencyimport AdSupport // Call when the first screen is visible, e.g. when scenePhase becomes .active.// Called from didFinishLaunching, the alert is never shown.@MainActor…Загрузку в App Store отклонили с ITMS-91053 из-за SDK, который писали не вы. Что декларирует privacy manifest и что проверяет Apple?
<plist version="1.0"><dict> <key>NSPrivacyTracking</key> <false/> <key>NSPrivacyTrackingDomains</key> <array/>…Каждый вызов аналитики закрыт флагом согласия, но вендор получает запрос ещё до ответа на диалог согласия. Откуда берётся этот запрос?
// AndroidManifest.xml: read before any of your code runs// <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />// <meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />// <meta-data android:name="google_analytics_default_allow_analytics_storage" android:value="false" /> data class Consent(val analytics: Boolean, val ads: Boolean, val crashes: Boolean)…Продукт хочет открыть приложение для детей младше 13 лет. Что меняется в декларациях сторов, в рекламном и аналитическом стеке и в том, какие данные вообще можно собирать?
enum class Audience { CHILD, TEEN, ADULT } // Applied once, before MobileAds.initialize()// AndroidManifest.xml: <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />fun configureForAudience(app: Application, audience: Audience) { val child = audience == Audience.CHILD…Пользователь нажимает «Удалить аккаунт». Что должно произойти помимо удаления строки пользователя и что вы обещаете насчёт бэкапов?
Ревьюер просит доказать, что приложение отправляет только то, что заявлено в форме Data safety. Какие доказательства вы можете предъявить?