android - 以编程方式设置 Always-On VPN,“管理员不拥有配置文件”
问题描述
我正在尝试弄清楚如何配置我的 VPN 应用程序以通过切换从应用程序内切换始终开启标志。
我知道
DevicePolicyManager#setAlwaysOnVpnPackage
但是,如何使用此功能还不是很清楚。我尝试了以下方法:
管理员.java
public class Admin extends DeviceAdminReceiver {
@Override
public void onEnabled(@NonNull Context context, @NonNull Intent intent) {
super.onEnabled(context, intent);
}
}
高级设置.java
public class AdvancedSettings extends AppCompatActivity
implements View.OnClickListener {
private ComponentName componentName;
private DevicePolicyManager devicePolicyManager;
private boolean alwaysOnConfiguredValue;
private static final int ALWAYS_ON_REQUEST_CODE = 11;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_advanced);
Button button = findViewById(R.id.toggleAlwaysOnButton);
button.setOnClickListener(this);
devicePolicyManager = (DevicePolicyManager) this
.getSystemService(Context.DEVICE_POLICY_SERVICE);
componentName = new ComponentName(
this.getApplicationContext(), Admin.class);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.toggleAlwaysOnButton) {
this.setAlwaysOn(true);
}
}
/**
* Handle the Activity Result.
*/
@Override
protected void onActivityResult(
int requestCode, int resultCode, @Nullable Intent data
) {
if (requestCode == ALWAYS_ON_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
finalizeAlwaysOnToggle();
} else {
Log.w(
"Invalid result code " + resultCode
);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* Start the process of enabling "Always On" for the VPN.
*
* @param boolean value
*/
private void setAlwaysOn(boolean value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
alwaysOnConfiguredValue = value;
if (devicePolicyManager.isAdminActive(componentName)) {
finalizeAlwaysOnToggle();
return;
}
requestAdminAccess();
} else {
Toas.makeText(this, "Not supported", Toast.LENGTH_LONG).show();
}
}
/**
* Request Admin Access for this application
* if it has not already been done.
*/
private void requestAdminAccess() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"This is required to modify the Always-On Feature from within the Test Application."
);
this.startActivityForResult(intent, ALWAYS_ON_REQUEST_CODE);
}
/**
* Finalize setting the always on toggle after the Admin Access
* has been granted for this application.
*/
private void finalizeAlwaysOnToggle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
if (devicePolicyManager.isAdminActive(componentName)) {
devicePolicyManager.setAlwaysOnVpnPackage(
componentName, (alwaysOnConfiguredValue) ? "com.myapp" : null, true
);
} else {
Log.e(
"Device Policy Manager Admin is not yet active while " +
"trying to finalize changes to AlwaysOnToggle."
);
}
} catch (PackageManager.NameNotFoundException e) {
Log.e("Unable to set always on vpn due to NameNotFound Exception.", e);
}
}
}
}
它可以很好地处理添加设备管理员的请求,但是在完成之后,当它运行时finalizeAlwaysOnToggle()
,在调用期间devicePolicyManager.setAlwaysOnVpnPackage
我收到以下错误:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp, PID: 30778
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=11, result=-1, data=null} to activity {com.myapp/com.myapp.ui.settings.AdvancedSettings}: java.lang.SecurityException: Admin ComponentInfo{com.myapp/com.myapp.provider.Admin} does not own the profile
解决方案
您必须区分“设备管理员”、“设备所有者”和“配置文件所有者”。正如文档中所述,您需要成为后两者之一才能调用setAlwaysOnVpnPackage
:
由设备或配置文件所有者调用,以通过特定应用程序为当前用户配置始终开启的 VPN 连接。此连接会在重新启动后自动授予并保持。
推荐阅读
- outlook - ics 文件附件未在 yahoo 和 outlook.live 中显示日历
- angular - 为什么 httpHeader 被添加为值
- python - 如何并行创建 python 对象
- extjs - 如何将树面板添加到 extjs 中的网格面板列
- java - 使用 Datastax 驱动程序 3.6 的 Cassandra 分页:不支持 Null 分页状态和获取大小
- javascript - 变量输出到控制台后返回函数的值
- swift - 使用 CTTelephonyNetworkInfo
- php - PHP 致命错误:未捕获的错误:在短代码中调用未定义的函数 aq_resize()
- processing - 如何在 Processing (v. 3.4) 中将元素附加到 3 维数组?
- react-native - React Navigation,在抽屉导航器外启动屏幕