强制应用程序从第一个活动重新启动(当权限被拒绝时)

29
众所周知,在Android 6.0中,如果在运行时拒绝权限并从最近菜单中恢复应用程序,则应用进程将被杀死并强制重新启动以防止任何安全问题:

enter image description here

值得注意的是,当应用程序从上次离开的Activity中恢复时,操作系统会记住用户最后浏览的Activity
不幸的是,这是一个问题,因为它会打破业务逻辑的流程。不能允许用户以这种方式在应用程序中间访问应用程序。
我的问题是,有没有办法强制应用程序从应用程序的第一个Activity重新启动,而不是从用户离开的页面开始?
是否有与应用程序重新启动/进程终止/权限切换相关联的任何回调函数?
这个做法是否错误?如果是,正确的做法是什么?
当然,这种行为以前已经被观察到了: 1. Android Preview M: activity recreates after permission grant 2. Application is getting killed after enable/disable permissions from settings on Android M nexus 6 3. Android Marshmallow: permissions change for running app

4. 点击“重置应用程序偏好设置”后,我的应用的所有权限都被撤销了

5. Android 6.0 权限 - 在设置中切换权限并返回应用时崩溃


1
直到您尝试使用需要该权限的某些功能时,您不需要知道您的应用程序是否具有特定权限。在那时,您需要采取通常的步骤:检查并(如有必要)请求。 - Michael
4
嗯,我没有尝试过这个,但我想你可以在 onResume 中调用 checkSelfPermission,如果失败了,就使用 FLAG_ACTIVITY_CLEAR_TASKFLAG_ACTIVITY_NEW_TASK 启动你的根活动。 - Michael
@Y.S. 你解决了这个问题吗? - Niko
1
@Niko:目前我甚至没有一个“不太优雅”的解决方案。你有吗? - Yash Sampat
@Y.S. 我使用了两个标志来检查这个问题。第一个是Activity onCreate参数Bundle savedInstanceState != null,第二个变量与我的内部业务逻辑相关。如果您没有这样的第二个变量,您可以将权限存储到共享首选项中,并在启动时检查它们是否已更改,然后存储静态标志,如果我让我的活动堆栈以错误的顺序“重新启动”,那么会出现问题。 - Niko
显示剩余25条评论
5个回答

1

您应该使用由onCreate提供的Bundle,由onSaveInstanceState保存的Bundle来处理Activity(重新)创建,更多信息在这里

Bundle中传递所有需要从先前状态中恢复并无缝还原UI所需的内容。您的Activity可能会因许多原因而重新创建,权限取消只是其中之一,屏幕旋转是另一个原因,因此只要您可以经受住其中之一,就可以经受住所有情况。


1

你是指这个吗?

MainActivity:

public class MainActivity extends AppCompatActivity {

TextView txt;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    txt = (TextView)findViewById(R.id.txt);

    txt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Intent intent = new Intent(MainActivity.this, ActivityB.class);
            intent.putExtra("from","MainActivity");
            startActivity(intent);
            finish();
        }
    });
}
}

ActivityB :
    public class ActivityB extends AppCompatActivity {

String intentTxt="";
final int MY_PERMISSIONS_REQUEST_PHONE_CALL = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    intentTxt = getIntent().getStringExtra("from");
}


@Override
protected void onResume() {
    super.onResume();
    if(intentTxt.equals("MainActivity")) {
        if (ContextCompat.checkSelfPermission(ActivityB.this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(ActivityB.this, new String[]{android.Manifest.permission.CALL_PHONE},
                    MY_PERMISSIONS_REQUEST_PHONE_CALL);
        }
    }
        intentTxt = "";
}

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

                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "32434"));
                startActivity(intent);

            } else {

                Intent intent = new Intent(ActivityB.this,MainActivity.class);
                startActivity(intent);
                finish();
            }
            return;
        }
    }
}
}

你可以在ActivityB的onRequestPermissionsResult中启动splashActivity / HomeActivity。在ActivityB的onResume中检查权限,以便在第一次调用ActivityB时和恢复时出现权限对话框。

0

我不知道是否还有人在寻找这个问题的答案,但我会通过反转逻辑来解决,而不是等待一个标志来指示由于权限被拒绝而重新启动/重新创建,传递一个标志来指示该Activity是由另一个Activity启动而不是系统重新创建。因此,如果extras中没有传入FLAG,则必须销毁活动堆栈并启动第一个活动。

希望能对某些人有所帮助。


0

您可以按照以下步骤进行操作。

  1. 创建一个扩展了 AppcompatActivity基础活动(Base Activity),以便在 onResume() 中维护所有权限并检查权限。
  2. 从所有活动中扩展 Base Activity
  3. 如果任何权限被拒绝,您可以从 Base Activity 中执行任何您想要的操作。

祝编码愉快! :)


0

你应该在onResume回调中放置代码来检查权限状态。如果用户切换到系统设置权限活动,您的Activity将被暂停。如果用户启用了某个权限并返回到您的Activity,则会调用onResume,此时您将有机会检查新权限。然后,您可以执行任何需要重新启动Activity的操作,例如使用具有FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TASK标志的Intent调用startActivity并再次启动您的Activity。

override fun onResume() {
  super.onResume()

  // check for permission
  checkPermissionsAndRestartIfNecessary()
}

private fun checkPermissionsAndRestartIfNecessary() {
  if (ContextCompat.checkSelfPermission(...) {
    ...
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接