Android M Permissions: onRequestPermissionsResult() не вызывается

Я обновляю наше приложение, чтобы использовать новую систему разрешений M. Все это работает помимо onRequestPermissionsResult (). Мне нужно проверить разрешение на нажатие кнопки, и если это удастся, отправьте текстовое сообщение. Когда я даю разрешение на это, диалоговое окно закрывается, но оно не запускает отправку текста, пока я снова не нажму кнопку.

Я отладил и установил точки останова в методе onRequestPermissionsResult (), но он никогда не входит в него.

этот метод сначала вызывается:

    private void askForPermission() {
    String[] permissions = new String[]{Manifest.permission.SEND_SMS};
    ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}

и тогда мой ответ выглядит так:

    @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == PERMISSIONS_CODE) {
        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            int grantResult = grantResults[i];

            if (permission.equals(Manifest.permission.SEND_SMS)) {
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    onPPSButtonPress();
                } else {
                    requestPermissions(new String[]{Manifest.permission.SEND_SMS}, PERMISSIONS_CODE);
                }
            }
        }
    }
}

кто-нибудь сталкивался с подобной проблемой? Ценю любую помощь в этом. Спасибо

22 ответов


Я столкнулся с такой же проблемой и я нашел решение. При использовании библиотеки поддержки необходимо использовать правильные вызовы методов. Например:

  • , когда в AppCompatActivity, вы должны использовать ActivityCompat.requestPermissions;
  • , когда в android.поддержка.В4.приложение.Фрагмент, вы должны использовать просто requestPermissions (это метод экземпляра андроид.поддержка.В4.приложение.Фрагмент)

Если вы вызываете ActivityCompat.requestPermissions в фрагменте,onRequestPermissionsResult обратный вызов вызывается для действия, а не фрагмента.

надеюсь, что это помогает!


вы можете попробовать это:

requestPermissions(permissions, PERMISSIONS_CODE);

Если вы вызываете этот код из фрагмента, он имеет собственный метод requestPermissions. Я считаю, что проблема в том, что вы вызываете статический метод.

Pro совет, если вы хотите onRequestPermissionsResult() В фрагмент: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)


Я надеюсь, что он работает нормально

Деятельность :

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

Для Фрагмент :

 requestPermissions(permissionsList,REQUEST_CODE);

я тоже столкнулся с этой проблемой. Если вы хотите действие, которое обрабатывает разрешения не в истории / recents, то у вас будет соблазн изменить свой AndroidManifest.xml запись.

если вы установите действие, которое вы вызываете requestPermissions или AppCompatActivity.requestPermissions С

android:noHistory="true"
android:excludeFromRecents="true"

в своем AndroidManifest.xml затем onRequestPermissionsResult() не будет называться. Это верно, если ваша деятельность происходит от Activity или AppCompatActivity.

это можно исправить, удалив оба флага из ' AndroidManifest.формате XML и завершение вашей деятельности с .


Если у вас onRequestPermissionsResult как в activity, так и в fragment обязательно вызовите super.onRequestPermissionsResult в активности. Это не требуется в фрагменте, но это в деятельности.


внутренний фрагмент, вам нужно позвонить:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

нет:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

Если вы используете requestPermissions во фрагменте, он принимает 2 параметра вместо 3.

вы должны использовать requestPermissions(permissions, PERMISSIONS_CODE);


Если по какой-то причине вы расширили пользовательское действие, расположенное во внешней библиотеке, которая не вызывает super, вам нужно будет вручную вызвать фрагмент super.onRequestPermissionsResult себя в вашей деятельности onRequestPermissionsResult.

YourActivity extends SomeActivityNotCallingSuperOnRequestPermissionsResult{
Fragment requestingFragment;//the fragment requesting the permission
...
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestingFragment!=null)
            requestingFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
...

у вас checkPermissions функция для устройств pre Marshmallow в FragmentCompat. Я использую так:

FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

я узнал, что важно, где вы называете android.support.v4.app.Fragment.requestPermissions.

если вы сделаете это в onCreate(), onRequestPermissionsResult() - это никогда не называл.

решение: вызовите его в onActivityCreated();

@Override
public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED) 
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);

}

эта проблема на самом деле была вызвана NestedFragments. В основном большинство фрагментов мы расширяем HostedFragment, который, в свою очередь, расширяет CompatFragment. Наличие этих вложенных фрагментов вызвало проблемы, которые в конечном итоге были решены другим разработчиком проекта.

Он делал некоторые низкоуровневые вещи, такие как переключение бит, чтобы заставить это работать, поэтому я не слишком уверен в фактическом окончательном решении


 /* use the object of your fragment to call the 
 * onRequestPermissionsResult in fragment after
 * in activity and use different request Code for 
 * both Activity and Fragment */

   if (isFragment)
    mFragment.requestPermissions(permissions.toArray(new
    String[permissions.size()]),requestPermission);

   else
    ActivityCompat.requestPermissions(mActivity,permissions.toArray(new
    String[permissions.size()]),requestPermission);

Это будет работать..

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

Если вы вызываете этот код из фрагмента, он имеет собственный метод requestPermissions.

таким образом, основная концепция, если вы находитесь в деятельности, то вызовите

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

и если во фрагменте, просто позвоните

requestPermissions(permissionsList,
                            permissionscode);

прежде чем вы проверите все согласно вышеуказанным ответам, убеждайтесь что ваш код запроса нет 0!!!

проверьте код onRequestPermissionsResult () в FragmentActivity.java:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    int index = (requestCode>>16)&0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode&0xffff, permissions, grantResults);
        }
    }
}

на основе goodgamerguy это решение:

myFragment.this.requestPermissions(....)

private void showContacts() {
    if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
    } else {
        doShowContacts();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        doShowContacts();
    }
}

можно использовать requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. Не используйте FragmentCompat, если вы используете v4.


UPDATE: видел чей-то ответ о вызове super.onRequestPermissionResult () в Activity и исправляет проблему кода запроса, о которой я упоминал, и вызывает onrequestpermissionresult фрагмента.

игнорировать этот материал:

для меня это вызывало onRequestPermissionResult активности, несмотря на то, что я вызывал фрагмент.requestPermission(...), Но он вернул результат с неправильным запросом (111 превратился в 65647 почему ??? Никогда не узнаю).

к счастью, это единственное разрешение, которое мы запрашиваем на этом экране, поэтому я просто игнорирую код запроса (у меня нет времени, чтобы выяснить, почему это не правильно прямо сейчас)


у меня есть удивительное решение для достижения этого сделать BaseActivity такой.

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));


}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case 1: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                CustomToast.getInstance().setCustomToast("Now you can share the Hack.");

            } else {
                Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

}

теперь йо может вызвать код, чтобы попросить разрешения, как это

 ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

теперь каждый раз, когда это происходит в любом месте, будь то в вашем фрагменте или в любой активности, будет вызываться базовая активность.

спасибо


подробности

  • Котлин 1.2.70
  • проверено в minSdkVersion 19
  • Android studio 3.1.4

алгоритм

модуль - камеры, расположение ....

  1. проверьте, если hasSystemFeature (если модуль в телефоне)
  2. проверьте, имеет ли пользователь доступ к модуль
  3. отправить запрос разрешений (попросите пользователя разрешить модуль использование)

особенности

  1. работа с действиями и фрагментами
  2. есть только один результат ответа
  3. можно проверить несколько модули в один запрос

решение

class PermissionType(val manifest_permission: String, val packageManager: String) {
    object Defined {
        val camera = PermissionType(Manifest.permission.CAMERA, PackageManager.FEATURE_CAMERA)
        val currentLocation = PermissionType(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.FEATURE_LOCATION_GPS)
    }
}

class  Permission {

    enum class PermissionResult {
        ACCESS_ALLOWED, ACCESS_DENIED, NO_SYSTEM_FEATURE;
    }

    interface ManagerDelegate {
        fun permissionManagerDelegate(result: Array<Pair<String, PermissionResult>>)
    }

    class Manager internal constructor(private val delegate: ManagerDelegate?) {

        private var context: Context? = null
        private var fragment: Fragment? = null
        private var activity: AppCompatActivity? = null
        private var permissionTypes: Array<PermissionType> = arrayOf()
        private val REQUEST_CODE = 999
        private val semaphore = Semaphore(1, true)
        private var result: Array<Pair<String, PermissionResult>> = arrayOf()


        constructor(permissionType: PermissionType, delegate: ManagerDelegate?): this(delegate) {
            permissionTypes = arrayOf(permissionType)
        }

        constructor(permissionTypes: Array<PermissionType>, delegate: ManagerDelegate?): this(delegate) {
            this.permissionTypes = permissionTypes
        }

        init {
            when (delegate) {
                is Fragment -> {
                    this.fragment = delegate
                    this.context = delegate.context
                }

                is AppCompatActivity -> {
                    this.activity = delegate
                    this.context = delegate
                }
            }
        }

        private fun hasSystemFeature(permissionType: PermissionType) : Boolean {
            return context?.packageManager?.hasSystemFeature(permissionType.packageManager) ?: false
        }

        private fun hasAccess(permissionType: PermissionType) : Boolean {
            return if (Build.VERSION.SDK_INT < 23) true else {
                context?.checkSelfPermission(permissionType.manifest_permission) == PackageManager.PERMISSION_GRANTED
            }
        }

        private fun sendRequest(permissionTypes: Array<String>) {

            if (fragment != null) {
                fragment?.requestPermissions(permissionTypes, REQUEST_CODE)
                return
            }

            if (activity != null){
                ActivityCompat.requestPermissions(activity!!, permissionTypes, REQUEST_CODE)
            }
        }

        fun check() {

            semaphore.acquire()
            AsyncTask.execute {
                var permissionsForSendingRequest: Array<String> = arrayOf()
                this.result = arrayOf()

                for (it in permissionTypes) {
                    if (!hasSystemFeature(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.NO_SYSTEM_FEATURE)
                        continue
                    }

                    if (hasAccess(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                    } else {
                        permissionsForSendingRequest += it.manifest_permission
                    }
                }

                if (permissionsForSendingRequest.isNotEmpty()) {
                    sendRequest(permissionsForSendingRequest)
                } else {
                    delegate?.permissionManagerDelegate(result)
                }
            }
        }

        fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            when (requestCode) {
                REQUEST_CODE -> {
                    if (grantResults.isEmpty()) {
                        return
                    }
                    for ((i,permission) in permissions.withIndex()) {
                        for (item in this.permissionTypes) {
                            if (permission == item.manifest_permission && i < grantResults.size) {
                                result += if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                                } else {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_DENIED)
                                }
                                break
                            }
                        }
                    }
                    delegate?.permissionManagerDelegate(result)
                }
            }
            semaphore.release()
        }
    }
}

использование в деятельности (во фрагменте то же самое)

class BaseActivity : AppCompatActivity(), Permission.ManagerDelegate {

    private lateinit var permissionManager: Permission.Manager

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

        permissionManager = Permission.Manager(arrayOf(PermissionType.Defined.camera, PermissionType.Defined.currentLocation), this)
        permissionManager.check()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }


    override fun permissionManagerDelegate(result: Array<Pair<String, Permission.PermissionResult>>) {
        result.forEach {
            println("!!! ${it.first} ${it.second}")
//            when (it.second) {
//                Permission.PermissionResult.NO_SYSTEM_FEATURE -> {
//                }
//
//                Permission.PermissionResult.ACCESS_DENIED  -> {
//                }
//
//                Permission.PermissionResult.ACCESS_ALLOWED -> {
//                }
//            }
        }
    }
}

У меня была аналогичная проблема, я нажимал кнопку, чтобы сделать вызов, который запускает callIntent. Сначала я проверил разрешение, если не предоставлено, я прошу разрешения и onRequestPermissionResult я вызываю разрешение проверки и снова звоню.

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case Constants.PERMISSIONS_REQUEST_CALL_PHONE: {
            if ( grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                checkPermissionsAndCall();
            }
        }
    }
}

public void checkPermissionsAndCall(){
    if (Build.VERSION.SDK_INT > 22) {
        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED){
            requestPermissions( new String[]{Manifest.permission.CALL_PHONE}, Constants.PERMISSIONS_REQUEST_CALL_PHONE);
        }
        else{
            callIntent();
        }
    }
}