2

我正在尝试为android编写一个VPN应用程序,无论我做什么,我的应用程序的“始终开启”设置似乎都是灰色的。

我在 android 文档的任何地方都找不到任何文档说明为什么可能不允许 VpnService 使用“始终开启”功能。

只是为了确保我清楚,如果我手动启用它,我的 VpnService 工作得很好。我可以毫无问题地连接、使用它等。我只是对为什么在 Android 设置中它在我的 Vpn 服务的“始终开启”切换下显示为“不支持此设备”感到困惑。

注意:我使用的是自定义协议,在某个论坛上,我确实看到过“谷歌不允许不使用谷歌白名单协议的 VPN 的 Always-On”,但是我在哪里找不到支持这一说法的文件,所以我怀疑这是原因。

我从阅读Android 文档中发现:

  1. 如果您在 Android Manafest 中的定义中显式提供SERVICE_META_DATA_SUPPORTS_ALWAYS_ON标志,其值将告诉系统您的应用程序不支持 Always On 功能。但是,如果您将其省略,则默认为. 所以应该没有必要提供这个。<service>falsetrue

  2. 根据AppManagementFragment.java#updateRestrictedViews中的 Android 源,它使用了一个函数mConnectivityManager.isAlwaysOnVpnPackageSupportedForUser(mUserId, mPackageName),但是我很难遵循这个函数的逻辑。查看ConnectivityManager.java#isAlwaysOnVpnPackageSupportedForUser时,它似乎最终出现在ConnectivityService.java#isAlwaysOnVpnPackageSupported最终指向Vpn.java#isAlwaysOnPackageSupported如果满足以下条件之一,这可能导致您的 VPN 被认为不支持始终开启:

    1. 传递给函数的包名称为空。
    2. 系统无法使用PackageManager. getApplicationInfoAsUser().
    3. 申请目标小于VERSION_CODES.N
    4. 该软件包中不包含任何 Vpn 服务AndroidManifest.xml
    5. 该包定义了任何 VpnServices,其SERVICE_META_DATA_SUPPORTS_ALWAYS_ON元数据设置为false.

注意:我的应用程序针对 API 29。

就是这样。

由于我的应用程序满足 中所述的所有要求Vpn.java#isAlwaysOnPackageSupported,我对它为什么不起作用感到非常困惑。

我创建了一个 android studio 项目来演示我的三星 Galaxy S10 上发生的这种情况。你可以在 github 上找到它

我的参考代码:

我的服务按照 Android 文档中的说明进行配置。

<service
    android:name=".provider.VpnProvider"
    android:enabled="true"
    android:permission="android.permission.BIND_VPN_SERVICE"
    android:description="@string/service_description"
    android:exported="false">
    <intent-filter>
        <action android:name="android.net.VpnSerivce" />
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</service>

在我的仪表板活动中,我使用它来处理Connect被点击的按钮。

public static final int REQ_START_VPN = 40;

public boolean connect() {
    Intent intent;

    try {
        intent = VpnProvider.prepare(this.getApplicationContext());
    } catch (IllegalStateException e) {
        return false;
    }

    if (intent != null) {
        try {
            this.startActivityForResult(intent, REQ_START_VPN);
            return true;
        } catch (ActivityNotFoundException e) {
            new BasicDialog(
                this, R.string.not_supported,
                R.string.not_supported_message
            ).show();
        }
    } else {
        this.onActivityResult(REQ_START_VPN, AppCompatActivity.RESULT_OK, null);
        return true;
    }
}

然后我使用以下方法处理结果:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == AppCompatActivity.RESULT_OK) {
        if (requestCode == REQ_START_VPN) {
            try {
                this.startService(new Intent(this, VpnProvider.class));
            } catch (IllegalStateException ignored) {}
        }
    }
}

我的VpnProvider类扩展VpnService并具有以下用于构建接口的内容:

VpnService.Builder builder = this.new Builder();
builder.setMtu(mtu);
builder.addAddress("1.2.3.4", 32);
builder.addDnsServer("8.8.8.8");
builder.addDnsServer("8.8.4.4");
builder.addRoute("0.0.0.0", 0);
vpnInterface = builder.establish();
4

1 回答 1

2

我发现了问题。

在我AndroidManifest.xml为我的服务声明意图过滤器时,我有一个错字。

<action android:name="android.net.VpnSerivce" />

代替

<action android:name="android.net.VpnService" />

这使得我的应用程序没有通知操作系统我的应用程序有一个VpnService,如 android 文档中所述。

这个错字花了我三天的时间,我再也不会回来了。

于 2019-08-19T16:28:36.203 回答