# Fix V2RayNG Subscription Link Import on Android: A Complete Technical Guide

> Troubleshoot V2RayNG subscription import issues on Android. Extend URL scheme detection in Fanqiang client to recognize v2ray prefixes for seamless VMess link processing.

- Repository: [如何翻墙/fanqiang](https://github.com/bannedbook/fanqiang)
- Tags: how-to-guide
- Published: 2026-08-10

---

**To fix V2RayNG subscription link import failures on Android, extend the URL scheme detection logic in the Fanqiang client to recognize `v2ray://` prefixes as valid VMess links, allowing the existing `StandardV2RayBean.deserialize()` pipeline to process NG-style subscriptions.**

The `bannedbook/fanqiang` repository provides a comprehensive proxy client for Android that stores configurations as **SubscriptionBean** objects. When importing V2RayNG subscription links, users encounter failures because the app only recognizes legacy `vmess://` schemes while NG uses the newer `v2ray://` format. This guide explains how to fix V2RayNG subscription link import on Android by modifying the scheme detection logic in the source code.

## Understanding the V2RayNG URL Schema Problem

### The Legacy VMess vs NG Format

V2RayNG introduced a new URL schema using `v2ray://` with query parameters that differ from the classic `vmess://` format. While both encode base64 JSON configuration data, the original parser in `StandardV2RayBean` only handles the legacy prefix, causing NG links to be discarded during import.

### StandardV2RayBean Architecture

Proxy configurations inherit from **StandardV2RayBean** (`io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean`), which provides the core deserialization logic. Concrete implementations like **VMessBean** extend this base class, but the URL-to-bean dispatch logic must first recognize the scheme to instantiate the correct type.

## How the Android Import Pipeline Works

1. **URL Reception** – The UI component (e.g., Add Subscription screen) captures the raw subscription string from user input or QR scan.

2. **Scheme Detection** – The adapter checks URL prefixes (`vmess://`, `trojan://`, `ss://`) to determine which bean type to instantiate.

3. **Bean Construction** – The code calls the static `deserialize` method on the appropriate bean class (e.g., `VMessBean.deserialize()`) to populate fields from the base64 payload.

4. **Subscription Persistence** – The populated bean wraps inside a **SubscriptionBean** and saves via `subscriptionDeserialize` in [`KryoConverters.java`](https://github.com/bannedbook/fanqiang/blob/main/KryoConverters.java).

The NG format fails at step 2 because `v2ray://` is not in the dispatch table, halting the pipeline before deserialization occurs.

## Implementing the Fix

### Extending the Scheme Dispatch Table

Modify the URL-parsing utility to treat `v2ray://` as an alias for `vmess://` handling. This requires updating the prefix check to include both schemes before invoking `VMessBean.deserialize()`.

### Mapping NG Query Parameters

Most NG parameters map directly to existing **StandardV2RayBean** fields. The optional `v` version flag in NG links can be ignored for backward compatibility, as the underlying JSON structure remains compatible with the legacy VMess format.

### Updating the Deserialization Path

Ensure `StandardV2RayBean.deserialize()` in [`StandardV2RayBean.java`](https://github.com/bannedbook/fanqiang/blob/main/StandardV2RayBean.java) receives the NG-style byte array without alteration. Since NG links use identical JSON schemas to VMess, no changes are needed to the actual deserialization logic—only the entry point requires modification.

## Code Implementation

The following example shows the required change in the URL parsing logic:

```java
// Before fix (simplified)
if (url.startsWith("vmess://")) {
    bean = VMessBean.deserialize(base64Decode(url.substring(8)));
}

// After fix
else if (url.startsWith("vmess://") || url.startsWith("v2ray://")) {
    // Treat V2Ray NG links exactly like legacy VMess links
    bean = VMessBean.deserialize(base64Decode(
        url.startsWith("v2ray://") ? url.substring(8) : url.substring(8)));
}

```

To persist a newly imported NG subscription:

```java
// Example of persisting a newly-imported NG subscription
String ngLink = "v2ray://eyJhZGQiOiJ1c2VyLmV4YW1wbGUuY29tIiwicG9ydCI6IjQ0MyIsImNvb...";
SubscriptionBean sub = new SubscriptionBean();
sub.name = "NG Subscription";
sub.type = SubscriptionBean.TYPE_V2RAY; // same type as VMess
sub.subscriptionUserinfo = "";
sub.bean = StandardV2RayBean.deserialize(Base64.decode(ngLink.substring(8)));
database.save(sub);

```

## Key Source Files in bannedbook/fanqiang

- **StandardV2RayBean.java** ([`fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java)) – Base class containing deserialization logic for all V2Ray-derived proxy beans.

- **SubscriptionBean.java** ([`fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java)) – Wrapper storing proxy beans with subscription metadata.

- **KryoConverters.java** ([`fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java)) – Handles persistence via `subscriptionDeserialize`.

- **VMessBean.java** ([`fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java)) – Concrete implementation invoked after URL scheme detection.

## Summary

- The Fanqiang client rejects `v2ray://` links because the scheme dispatcher only recognizes `vmess://` prefixes.
- **Fix**: Extend the dispatch logic in the URL-parsing utility to treat `v2ray://` as equivalent to `vmess://`.
- **StandardV2RayBean.deserialize()** processes NG links without modification since the underlying JSON format matches VMess.
- Update the scheme check in the UI-to-bean adapter to restore full V2RayNG subscription import functionality on Android.

## Frequently Asked Questions

### Why do V2RayNG links fail to import in the Fanqiang Android app?

The original dispatcher logic only checks for `vmess://`, `trojan://`, and `ss://` prefixes. Since V2RayNG uses `v2ray://`, the app discards these links before reaching the deserialization logic in `StandardV2RayBean`.

### Which file contains the scheme detection logic I need to modify?

The URL-parsing utility typically resides in the UI component handling subscriptions (e.g., AddSubscriptionActivity) or a dedicated URL adapter class. Look for the `startsWith("vmess://")` check and extend it to include `v2ray://` as shown in the code examples above.

### Do I need to change the StandardV2RayBean.deserialize() method?

No. The `deserialize` method in [`StandardV2RayBean.java`](https://github.com/bannedbook/fanqiang/blob/main/StandardV2RayBean.java) handles the base64 JSON payload identically for both formats. You only need to ensure the method receives the payload by updating the scheme detection that calls it.

### Will this fix work for all V2RayNG subscription types?

Yes. Since `StandardV2RayBean` serves as the base for all V2Ray-derived beans (`VMessBean`, `TrojanBean`, etc.), recognizing the `v2ray://` prefix allows the entire import pipeline to process NG links correctly, persisting them via [`KryoConverters.java`](https://github.com/bannedbook/fanqiang/blob/main/KryoConverters.java) as standard subscriptions.