Play Console 上的 Query_all_packages 权限被拒绝 - 如何解决?

问题描述 投票:0回答:1

我的 Query_all_packages 权限请求在 Play 管理中心被拒绝。还有其他解决方案吗?我希望在按下“打开应用程序”按钮后打开应用程序进行确认,但该代码适用于较旧的手机,但不适用于运行 Android 11 及更高版本的设备。

我已经尝试了大部分代码,但无法解决与权限相关的问题。我已经为此苦苦挣扎了3天了

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.testing.brctestingcommunity">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
    <uses-permission android:name="android.permission.GET_TASKS" />


    <application
        android:allowBackup="false"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@drawable/brctesting"
        android:label="@string/app_name"
        android:roundIcon="@drawable/brctesting"
        android:supportsRtl="true"
        android:theme="@style/Theme.BrcTestingCommunity"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".LoginRegisterActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity" />

        <activity
            android:name=".AddAppActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity" />

        <activity
            android:name=".AppDetailActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity" />

        <activity
            android:name=".WebLinkActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity" />

        <!-- UserAppsActivity Eklendi -->
        <activity
            android:name=".UserAppsActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BrcTestingCommunity" />


        <activity android:name=".PoliciesActivity" />
        <activity android:name=".RefundPolicyActivity" />
        <activity android:name=".ShippingPolicyActivity" />
        <activity android:name=".TermsConditionsActivity" />
        <activity android:name=".PrivacyPolicyActivity" />
        <activity android:name=".StepsActivity" />
        <activity android:name=".VideoActivity" />
        <activity android:name=".GuideActivity" />

    </application>

</manifest>

package com.testing.brctestingcommunity

import android.app.Dialog
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.imageview.ShapeableImageView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.FirebaseFirestore
import java.util.concurrent.TimeUnit

class AppDetailActivity : AppCompatActivity() {

    private lateinit var webLinkLauncher: ActivityResultLauncher<Intent>
    private lateinit var feedbackLauncher: ActivityResultLauncher<Intent>
    private lateinit var webLinkButton: Button
    private lateinit var androidLinkButton: Button
    private lateinit var countdownTextView: TextView
    private val userId = FirebaseAuth.getInstance().currentUser?.uid
    private val db = FirebaseFirestore.getInstance()
    private var shouldShowFeedbackPopup: Boolean = false
    private var shouldShowOpenAppPopup: Boolean = false
    private var feedbackGiven: Boolean = false
    private var pointsAwardedForFeedback: Boolean = false // Kullanıcının geri bildirim puanı alıp almadığını kontrol eder
    private val feedbackPoints = 5
    private val webLinkPoints = 5 // WebLink için verilecek puan

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_app_detail)

        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.title = getString(R.string.app_details)

        toolbar.setNavigationOnClickListener {
            onBackPressedDispatcher.onBackPressed()
        }

        loadDataFromIntent(intent)

        webLinkButton = findViewById(R.id.web_link_button)
        androidLinkButton = findViewById(R.id.android_link_button)
        countdownTextView = findViewById(R.id.countdown_text_view) // Geri sayım için TextView

        webLinkLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                addPointsToUser(webLinkPoints)
                Toast.makeText(this, "You earned $webLinkPoints points!", Toast.LENGTH_LONG).show()
                webLinkButton.visibility = View.GONE // WebLink butonunu gizle
                saveWebLinkStatusToFirestore()
            }
        }

        feedbackLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { _ ->
            if (feedbackGiven && !pointsAwardedForFeedback) {
                addPointsToUser(feedbackPoints)
                Toast.makeText(this, "Thank you for your feedback! You earned $feedbackPoints points.", Toast.LENGTH_LONG).show()
                pointsAwardedForFeedback = true
                saveFeedbackGivenStatusToFirestore()
                saveLastInteractionTime() // Zaman damgasını kaydet
                startCountdown(24 * 60 * 60 * 1000) // 24 saatlik geri sayım başlat
                androidLinkButton.visibility = View.GONE // Butonu gizle
                countdownTextView.visibility = View.VISIBLE // Geri sayım göster
            }
        }

        webLinkButton.setOnClickListener {
            val webLink = intent.getStringExtra("webLink")
            if (!webLink.isNullOrEmpty()) {
                openLinkInWebView(webLink)
            } else {
                Toast.makeText(this, getString(R.string.no_web_link_provided), Toast.LENGTH_SHORT).show()
            }
        }

        androidLinkButton.setOnClickListener {
            val androidLink = intent.getStringExtra("androidLink")
            if (!androidLink.isNullOrEmpty()) {
                shouldShowOpenAppPopup = true
                shouldShowFeedbackPopup = true
                openPlayStoreLink(androidLink)
            } else {
                Toast.makeText(this, getString(R.string.no_android_link_provided), Toast.LENGTH_SHORT).show()
            }
        }

        // Buton durumlarını kontrol et
        checkButtonVisibility()

        checkAndInitializeUser()
    }

    override fun onResume() {
        super.onResume()

        if (shouldShowOpenAppPopup) {
            showOpenAppPopup()
            shouldShowOpenAppPopup = false
        } else if (shouldShowFeedbackPopup) {
            showFeedbackPopup()
            shouldShowFeedbackPopup = false
        }

        // Butonların görünürlüğünü her geri dönüşte kontrol edin
        checkButtonVisibility()
    }

    private fun loadDataFromIntent(intent: Intent) {
        val appLogo: ShapeableImageView = findViewById(R.id.app_logo)
        val appName: TextView = findViewById(R.id.app_name)
        val developerName: TextView = findViewById(R.id.developer_name)
        val postDate: TextView = findViewById(R.id.post_date)
        val credits: TextView = findViewById(R.id.credits)
        val appDescription: TextView = findViewById(R.id.app_description)

        val logoUrl = intent.getStringExtra("logoUrl")
        val name = intent.getStringExtra("name")
        val developer = intent.getStringExtra("developer")
        val date = intent.getStringExtra("date")
        val creditsValue = intent.getIntExtra("credits", 0)
        val description = intent.getStringExtra("description")

        Glide.with(this)
            .load(logoUrl)
            .apply(RequestOptions().transform(CenterCrop(), RoundedCorners(16)))
            .into(appLogo)

        appName.text = name
        developerName.text = developer
        postDate.text = getString(R.string.posted_on, date)
        credits.text = getString(R.string.credits, creditsValue)
        appDescription.text = description
    }

    private fun openLinkInWebView(url: String) {
        val intent = Intent(this, WebLinkActivity::class.java).apply {
            putExtra("url", url)
            putExtra("logoUrl", [email protected]("logoUrl"))
            putExtra("name", [email protected]("name"))
            putExtra("developer", [email protected]("developer"))
            putExtra("date", [email protected]("date"))
            putExtra("credits", [email protected]("credits", 0))
            putExtra("description", [email protected]("description"))
            putExtra("webLink", [email protected]("webLink"))
            putExtra("androidLink", [email protected]("androidLink"))
        }
        webLinkLauncher.launch(intent)
    }

    private fun openPlayStoreLink(url: String) {
        try {
            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
            }
            startActivity(intent)
            Log.d("AppDetailActivity", "Play Store link opened: $url")
        } catch (e: Exception) {
            Log.e("AppDetailActivity", "Play Store link could not be opened: $url", e)
            Toast.makeText(this, "Failed to open the Play Store link.", Toast.LENGTH_LONG).show()
        }
    }

    private fun checkButtonVisibility() {
        val webLink = intent.getStringExtra("webLink")
        val androidLink = intent.getStringExtra("androidLink")

        if (userId != null) {
            val userRef = db.collection("users").document(userId)

            userRef.get().addOnSuccessListener { document ->
                if (document.exists()) {
                    val earnedUrls = document.get("earnedUrls") as? List<*>
                    if (earnedUrls != null && earnedUrls.contains(webLink)) {
                        webLinkButton.visibility = View.GONE
                    } else {
                        webLinkButton.visibility = View.VISIBLE
                    }

                    val feedbackGivenForUrls = document.get("feedbackGivenForUrls") as? List<*>
                    val lastInteractionTime = document.getLong("lastInteractionTime") ?: 0L
                    val currentTime = System.currentTimeMillis()
                    val elapsedTime = currentTime - lastInteractionTime

                    if (feedbackGivenForUrls != null && feedbackGivenForUrls.contains(androidLink)) {
                        if (elapsedTime < 24 * 60 * 60 * 1000) {
                            androidLinkButton.visibility = View.GONE
                            countdownTextView.visibility = View.VISIBLE
                            startCountdown(24 * 60 * 60 * 1000 - elapsedTime)
                        } else {
                            androidLinkButton.visibility = View.VISIBLE
                            countdownTextView.visibility = View.GONE
                        }
                    } else {
                        androidLinkButton.visibility = View.VISIBLE
                        countdownTextView.visibility = View.GONE
                    }
                }
            }.addOnFailureListener { e ->
                Log.e("AppDetailActivity", "Failed to check button visibility: $e")
            }
        }
    }

    private fun extractPackageNameFromUrl(url: String): String? {
        return try {
            val uri = Uri.parse(url)
            uri.getQueryParameter("id") ?: uri.lastPathSegment.also {
                Log.d("AppDetailActivity", "Extracted package name: $it")
            }
        } catch (e: Exception) {
            Log.e("AppDetailActivity", "Failed to extract package name from URL: $url", e)
            null
        }
    }

    private fun openInstalledApp(packageName: String) {
        Log.d("AppDetailActivity", "Trying to open the app: $packageName")
        try {
            val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            if (intent != null) {
                startActivity(intent)
                Log.d("AppDetailActivity", "App opened: $packageName")
            } else {
                Log.d("AppDetailActivity", "App not found: $packageName")
                Toast.makeText(
                    this,
                    "App is not installed or you are not part of the test group. Make sure you are signed in with the correct Google account.",
                    Toast.LENGTH_LONG
                ).show()
            }
        } catch (e: Exception) {
            Log.e("AppDetailActivity", "Error while trying to open the app: $packageName", e)
            Toast.makeText(this, "Failed to open the app due to an error.", Toast.LENGTH_LONG).show()
        }
    }

    private fun showOpenAppPopup() {
        val dialog = Dialog(this)
        dialog.setContentView(R.layout.popup_layout) // Burada doğru layout dosyasını kullanın
        val openAppButton = dialog.findViewById<Button>(R.id.openAppButton)

        openAppButton.setOnClickListener {
            val androidLink = intent.getStringExtra("androidLink")
            if (!androidLink.isNullOrEmpty()) {
                val appPackageName = extractPackageNameFromUrl(androidLink)
                if (!appPackageName.isNullOrEmpty() && isAppInstalled(appPackageName)) {
                    openInstalledApp(appPackageName)
                    shouldShowFeedbackPopup = true
                } else {
                    Toast.makeText(this, getString(R.string.app_not_installed), Toast.LENGTH_SHORT).show()
                }
            }
            dialog.dismiss()
        }
        dialog.show()
    }

    private fun showFeedbackPopup() {
        val dialog = Dialog(this)
        dialog.setContentView(R.layout.popup_feedback_layout)
        val feedbackButton = dialog.findViewById<Button>(R.id.feedbackButton)

        feedbackButton.setOnClickListener {
            val androidLink = intent.getStringExtra("androidLink")
            if (!androidLink.isNullOrEmpty()) {
                val appPackageName = extractPackageNameFromUrl(androidLink)
                if (!appPackageName.isNullOrEmpty()) {
                    feedbackGiven = true // Mark as feedback given before redirecting
                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName"))
                    feedbackLauncher.launch(intent)
                } else {
                    Toast.makeText(this, "Invalid app link", Toast.LENGTH_SHORT).show()
                }
            } else {
                Toast.makeText(this, "No app link provided", Toast.LENGTH_SHORT).show()
            }
            dialog.dismiss()
        }
        dialog.show()
    }

    private fun isAppInstalled(packageName: String): Boolean {
        return try {
            packageManager.getPackageInfo(packageName, 0)
            Log.d("AppDetailActivity", "App is installed: $packageName")
            true
        } catch (e: PackageManager.NameNotFoundException) {
            Log.d("AppDetailActivity", "App is not installed: $packageName")
            false
        }
    }

    private fun addPointsToUser(points: Int) {
        userId?.let { uid ->
            val userRef = db.collection("users").document(uid)
            userRef.update("points", FieldValue.increment(points.toLong()))
                .addOnSuccessListener {
                    Log.d("AppDetailActivity", "$points points added to user.")
                }
                .addOnFailureListener { e ->
                    Log.e("AppDetailActivity", "Error adding points: ", e)
                    Toast.makeText(this, "Failed to add points", Toast.LENGTH_LONG).show()
                }
        }
    }

    private fun saveFeedbackGivenStatusToFirestore() {
        userId?.let { uid ->
            val androidLink = intent.getStringExtra("androidLink")
            if (androidLink != null) {
                val userRef = db.collection("users").document(uid)
                userRef.update("feedbackGivenForUrls", FieldValue.arrayUnion(androidLink))
                    .addOnSuccessListener {
                        Log.d("AppDetailActivity", "Feedback given status saved for $androidLink.")
                    }
                    .addOnFailureListener { e ->
                        Log.e("AppDetailActivity", "Error saving feedback given status: $androidLink", e)
                    }
            }
        }
    }

    private fun saveWebLinkStatusToFirestore() {
        userId?.let { uid ->
            val webLink = intent.getStringExtra("webLink")
            if (webLink != null) {
                val userRef = db.collection("users").document(uid)
                userRef.update("earnedUrls", FieldValue.arrayUnion(webLink))
                    .addOnSuccessListener {
                        Log.d("AppDetailActivity", "WebLink status saved for $webLink.")
                    }
                    .addOnFailureListener { e ->
                        Log.e("AppDetailActivity", "Error saving WebLink status: $webLink", e)
                    }
            }
        }
    }

    private fun saveLastInteractionTime() {
        userId?.let { uid ->
            val userRef = db.collection("users").document(uid)
            userRef.update("lastInteractionTime", System.currentTimeMillis())
                .addOnSuccessListener {
                    Log.d("AppDetailActivity", "Last interaction time saved.")
                }
                .addOnFailureListener { e ->
                    Log.e("AppDetailActivity", "Error saving last interaction time: ", e)
                }
        }
    }

    private fun startCountdown(millisUntilFinished: Long) {
        val countdownTimer = object : CountDownTimer(millisUntilFinished, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                val hours = TimeUnit.MILLISECONDS.toHours(millisUntilFinished)
                val minutes = TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60
                val seconds = TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
                val timeFormatted = String.format("%02d:%02d:%02d", hours, minutes, seconds)
                countdownTextView.text = "Button will be active in: $timeFormatted"
            }

            override fun onFinish() {
                countdownTextView.visibility = View.GONE
                androidLinkButton.visibility = View.VISIBLE
            }
        }
        countdownTimer.start()
    }

    private fun checkAndInitializeUser() {
        val userId = FirebaseAuth.getInstance().currentUser?.uid
        if (userId != null) {
            val userRef = FirebaseFirestore.getInstance().collection("users").document(userId)
            userRef.get().addOnSuccessListener { document ->
                if (!document.exists()) {
                    initializeUserInFirestore(userId) // Eğer kullanıcı Firestore'da yoksa başlat
                }
            }.addOnFailureListener { e ->
                Log.e("AppDetailActivity", "Error checking user in Firestore: $userId", e)
            }
        }
    }

    private fun initializeUserInFirestore(userId: String) {
        val userRef = FirebaseFirestore.getInstance().collection("users").document(userId)
        val userData = hashMapOf(
            "points" to 0,
            "earnedUrls" to emptyList<String>(),
            "feedbackGivenForUrls" to emptyList<String>(),
            "lastInteractionTime" to 0L
        )

        userRef.set(userData)
            .addOnSuccessListener {
                Log.d("AppDetailActivity", "User initialized in Firestore: $userId")
            }
            .addOnFailureListener { e ->
                Log.e("AppDetailActivity", "Failed to initialize user in Firestore: $userId", e)
            }
    }
}

android package
1个回答
0
投票

Google 已经明确表示,

QUERY_ALL_PACKAGES
是一种特殊情况,只有当您的应用程序属于某种类型(例如应用程序启动器)时才会被授予。

我在一家大量使用包管理的公司工作,为了支持 Android 11,我们必须接受一些更改并改变我们的工作方式,例如:

  • 对于我们知道必须支持的包名称,请将它们添加到清单(
    <queries>
    部分),然后您可以像在早期版本的 Android 上一样查询它们
  • 对于我们在构建时不一定知道名称的任意软件包,我们必须接受无法检测该软件包是否安装在设备上的事实。我们只是向用户显示更多通用错误,例如“我们无法启动该应用程序,请检查它是否已安装”等
  • 即使您无法查询包,您仍然可以启动应用程序。但您必须知道要启动的 Activity 类。我们必须开发一个解决方案,让服务器向我们发送特定应用程序的活动类名称。您可以通过
    intent.setClassName(...)
    执行此操作,我们仅对在构建时不知道包名称的包使用此解决方案(否则我们可以将它们放入清单中并避免这种复杂性)
© www.soinside.com 2019 - 2024. All rights reserved.