Mobile Development 13 min read

How a Single Config Line Enables Dynamic Page Redirection in Mobile Apps

This article explains the background pain points of hard‑coded cross‑stack navigation in a mobile app, describes a dynamic routing component built on URL interception, regex matching and replacement, shows Kotlin and iOS implementations, and demonstrates real‑world cases in an app center and order module.

Youzan Coder
Youzan Coder
Youzan Coder
How a Single Config Line Enables Dynamic Page Redirection in Mobile Apps

Background and pain points: mobile apps increasingly contain native, H5, Weex and Flutter pages, and hard‑coded navigation logic makes version‑driven changes costly, cross‑stack adaptation expensive, and special WebView handling difficult.

Solution overview: a dynamic routing component was created to centralise all navigation, fetch configurable routing rules from a config centre, match URLs with regular expressions, and replace them with target routes at runtime.

Implementation Details

1.1 Route Interception + Replacement

In the micro‑mall client, page navigation is already decoupled via a component called ZanURLRouter. Its responsibilities are:

Register routes and pages at startup

Find the correct page for navigation

Without affecting external interfaces, the target‑route parsing step was extended to invoke the dynamic router.

Example conversion: youzan://orderlist?type=1&status=2 to

wsc://orderlist/v2?type=1&status=2

1.2 Routing Rule Configuration

The key node is a rule list stored in the Youzan mobile config centre, version‑aware and delivered dynamically. Each rule consists of a regex Key and a JSON Value template.

Key: ^youzan://orderlist\?type=(\d+)&status=(\d+)$
Value: {"template": "wsc://orderlist/v2?type=$1&status=$2"}

The rule is abstracted as an entity class:

class Rule {
    // URL matching pattern (regex)
    String pattern;
    // Replacement template
    String template;
}

1.2.2 Abstract Interface

After configuring rules, three core methods are needed:

// Register replacement rule
fun initWithPattern(Rule rule)
// Check whether a route matches a registered pattern
fun testWithRoute(String routeUrl): Boolean
// Get the replaced navigation address
fun appliedWithRoute(String routeUrl): String

The dynamic router pulls the rule table at application start, parses and stores it. When ZanURLRouter resolves a target route, each rule is tested; a hit triggers the replacement and the router proceeds with the new URL.

1.3 Route Replacement

The core logic relies on regular expressions for two scenarios:

Regex validation to determine rule hit

Regex replacement to rewrite the URL text

Both Android and iOS provide built‑in regex APIs:

/* ------------ Android ------------ */
// Match validation
Pattern.matcher(String text)
// Replace
Regex.replace(String input, String replacement)

/* ------------ iOS ------------ */
(NSString *)stringByReplacingMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)templ;

1.4 Parameter Handling

Most navigation URLs carry parameters. After replacement, parameters must be transferred between native and web pages. Android uses Intent for parameter storage; only primitive types are supported in the dynamic router. A Kotlin helper builds a query string from a Bundle:

fun appendBundleParams(strBuilder: StringBuilder, bundle: Bundle) {
    val keySet = bundle.keySet()
    for (key in keySet) {
        bundle[key]?.let { value ->
            when (value) {
                is Bundle -> appendBundleParams(strBuilder, value)
                is String, is Int, is Long, is Double, is Float, is Char, is Boolean, is Short -> {
                    if (strBuilder.isNotEmpty()) {
                        strBuilder.append("&")
                    }
                    strBuilder.append("$key=$value")
                }
                else -> { /* ignore */ }
            }
        }
    }
}

For H5‑to‑native navigation, an Intent extension extracts primitive parameters, falling back to string conversion when needed:

fun Intent.getIntFromRouter(key: String, defaultValue: Int): Int {
    val extras = this.extras
    if (extras == null || !this.hasExtra(key)) {
        return defaultValue
    }
    return extras.get(key) as? Int ?: (this.getStringExtra(key)?.toInt() ?: defaultValue)
}

1.5 URLEncode Edge Cases

When URLs are URL‑encoded, direct regex matching fails. The solution decodes the string for matching but preserves encoding during replacement. A helper records the positions of encoded characters and performs a manual replace:

private fun getEncodeCharMap(url: String, encodeUrl: String): Map<Int, IntRange> {
    if (Uri.decode(encodeUrl) != url) {
        return mapOf()
    }
    val urlChars = url.toCharArray()
    val urlEncodeChars = encodeUrl.toCharArray()
    var i = 0
    var j = 0
    val encodeMap = mutableMapOf<Int, IntRange>()
    while (i < urlChars.size && j < urlEncodeChars.size) {
        if (urlChars[i] != urlEncodeChars[j]) {
            val s = Uri.encode(urlChars[i].toString())
            val range = IntRange(j, j + s.length - 1)
            encodeMap[i] = range
            j += s.length
        } else {
            j++
        }
        i++
    }
    return encodeMap
}

Real‑World Application Cases

Application Center : The app center lists many entry points. iOS uses wsc://shop/management, Android uses wsc://team/management, while the server delivers wsc://team/management. Adding a rule that maps the iOS URL to the Android one solves the inconsistency without code changes.

Order Module Refactor : During the micro‑mall order module reconstruction, the new module co‑exists with the legacy one. Dynamic routing is used to map old URLs to new ones during a gray‑release phase, ensuring seamless user experience. (See the detailed “Micro‑mall Order Module Refactor Practice” article for full code.)

Conclusion

Dynamic routing turns simple regex matching and replacement into a powerful URL redirection service for mobile clients, handling cross‑platform differences, feature toggles, and gradual migrations. The component is a key part of Youzan’s mobile‑side componentisation and dynamic configuration strategy, and its design can inspire similar solutions in other mobile ecosystems.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MobileiOSAndroidDynamic ConfigurationKotlinrouting
Youzan Coder
Written by

Youzan Coder

Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.