这是一个非常常见的需求,但也是一个容易出坑的地方,核心问题在于:URL 本身是一个纯文本协议,它不能直接包含非 ASCII 字符(如中文),我们必须对中文字符进行“编码”,将它们转换成 URL 安全的格式。

下面我将分平台(iOS、Android、Web)并结合不同场景(URL Scheme、Universal Link/App Link、普通 HTTP URL)来详细说明。
核心概念:URL 编码
在处理中文参数前,必须理解 URL 编码。
-
什么是 URL 编码? 它将 URL 中不允许的字符(如空格、中文、
&, , 等)转换成 加上两位十六进制数的形式。- 空格 (
`) 会被编码为%20或+`。 - 中文字符 "你" 会被编码为
%E4%BD%A0。
- 空格 (
-
为什么必须编码?
(图片来源网络,侵删)- 协议限制:URL 协议本身规定只能使用 ASCII 字符集。
- 特殊字符冲突:
&用于分隔参数, 用于分隔键和值, 标识查询字符串的开始,如果参数中包含这些字符,不编码就会导致 URL 结构错乱,解析失败。 - 安全性和兼容性:编码可以确保 URL 在不同的浏览器、服务器和客户端之间正确传输和解析,避免乱码。
URL Scheme 跳转(App 间跳转)
这是最需要小心处理中文参数的场景,因为不同平台和实现方式对编码的要求不同。
iOS (Swift/Objective-C)
在 iOS 中,最佳实践是手动对参数进行 URL 编码。URLComponents 类是处理这个问题的现代、安全且推荐的方式。
步骤:
- 创建一个
URLComponents对象。 - 设置
scheme,host,path。 - 创建一个
URLQueryItem数组,将你的键值对(包含中文)放进去。 - 将
queryItems赋值给URLComponents。URLComponents会自动对name(键) 和value(值) 进行编码。 - 从
URLComponents中获取url,这个url的字符串表示就是已经编码好的 URL。
示例代码 (Swift):

import UIKit
func jumpToAppWithChineseParams() {
// 1. 创建 URLComponents 对象
var components = URLComponents()
// 2. 设置 Scheme 和 Host
components.scheme = "myappscheme"
components.host = "openpage"
// 3. 准备带中文的参数
let userName = "张三"
let orderID = "订单#123"
// 4. 创建 QueryItem 并赋值给 components
// URLComponents 会自动处理编码
components.queryItems = [
URLQueryItem(name: "user", value: userName),
URLQueryItem(name: "order", value: orderID)
]
// 5. 获取最终的 URL
guard let url = components.url else {
print("URL 构建失败")
return
}
print("最终的 URL: \(url.absoluteString)")
// 输出: myappscheme://openpage?user=%E5%BC%A0%E4%B8%89&order=%E8%AE%A2%E5%8D%95%23123
// 6. 使用 openURL 进行跳转
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:]) { success in
if !success {
print("打开 App 失败")
}
}
} else {
// Fallback for iOS 9 and below
UIApplication.shared.openURL(url)
}
}
// 调用函数
jumpToAppWithChineseParams()
重要提醒:
- 不要手动拼接字符串:像
let urlString = "myappscheme://openpage?user=\(userName)"这种方式是错误的,因为它不会对中文和特殊字符进行编码,极大概率会导致接收方解析失败。 - 接收方如何解析? 接收 App 在接收到 URL 后,同样可以使用
URLComponents来解析queryItems,它会自动解码,你得到的就是原始的中文字符串。
Android (Kotlin/Java)
在 Android 中,处理方式与 iOS 类似,也是手动对参数进行编码。
步骤:
- 构建
Uri.Builder。 - 依次添加
scheme,host,path。 - 使用
appendQueryParameter(key, value)方法添加参数。这个方法会自动对键和值进行编码。 - 调用
build()得到最终的Uri对象。
示例代码 (Kotlin):
import android.net.Uri
import android.content.Intent
fun jumpToAppWithChineseParams() {
// 1. 准备带中文的参数
val userName = "李四"
val orderID = "订单&456"
// 2. 使用 Uri.Builder 构建链接
// appendQueryParameter 会自动处理编码
val uri = Uri.Builder()
.scheme("myappscheme")
.authority("openpage") // host
.appendQueryParameter("user", userName)
.appendQueryParameter("order", orderID)
.build()
// 3. 获取最终的 URL 字符串
val urlString = uri.toString()
println("最终的 URL: $urlString")
// 输出: myappscheme://openpage?user=%E6%9D%8E%E5%9B%BD&order=%E8%AE%A2%E5%8D%95%26456
// 4. 创建 Intent 并跳转
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(intent)
} catch (e: Exception) {
println("打开 App 失败: ${e.message}")
}
}
// 调用函数
jumpToAppWithChineseParams()
重要提醒:
- 同样不要手动拼接:
"myappscheme://openpage?user=" + userName是错误的。 - 接收方如何解析? 接收方使用
intent.data获取Uri后,可以直接通过uri.getQueryParameter("user")来获取解码后的值。
Universal Link / App Link (HTTP/HTTPS URL)
这种方式主要用于从网页或系统浏览器跳转到 App,并且可以传递参数,处理中文参数的原则和 URL Scheme 完全一样:必须对参数进行 URL 编码。
无论是通过 JavaScript 在网页端生成跳转链接,还是在服务器端生成跳转链接,都需要对中文参数进行编码。
网页端示例 (JavaScript):
function jumpToApp() {
const userName = "王五";
const orderID = "订单@789";
// 使用 encodeURIComponent 进行编码
// 注意:需要对 value 和 key 分别编码
const encodedUser = encodeURIComponent(userName);
const encodedOrder = encodeURIComponent(orderID);
const url = `https://yourdomain.com/openpage?user=${encodedUser}&order=${encodedOrder}`;
console.log("最终的 URL:", url);
// 输出: https://yourdomain.com/openpage?user=%E7%8E%8B%E4%BA%94&order=%E8%AE%A2%E5%8D%95%40789
// 使用 Universal Link 跳转
window.location.href = url;
}
App 端处理: App 端接收到 Universal Link 后,解析 URL 的方式和处理 URL Scheme 的方式完全相同。
- iOS: 使用
URLComponents解析queryItems。 - Android: 使用
Uri解析getQueryParameter。
从 App 跳转到网页 (打开外部浏览器)
这个场景下,你的 App 是“发送方”,需要构造一个包含中文参数的 HTTP URL,然后用系统浏览器打开,处理方式依然相同:必须对参数进行 URL 编码。
iOS 示例 (Swift):
func openWebPageWithChineseParams() {
let searchQuery = "北京 美食"
// 使用 URLComponents 或 addingPercentEncoding
var components = URLComponents()
components.scheme = "https"
components.host = "www.baidu.com"
components.path = "/s"
// 对查询值进行编码
let encodedQuery = searchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
components.queryItems = [URLQueryItem(name: "wd", value: encodedQuery)]
guard let url = components.url else { return }
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
Android 示例 (Kotlin):
fun openWebPageWithChineseParams() {
val searchQuery = "上海 旅游"
// 使用 Uri.Builder 或 Uri.encode
val encodedQuery = Uri.encode(searchQuery)
val url = "https://www.baidu.com/s?wd=$encodedQuery"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
}
总结与最佳实践
-
核心原则:永远不要在 URL 中直接使用未经编码的中文字符或特殊字符。
-
统一编码:无论是 iOS、Android 还是 Web,发送方(构造 URL 的一方)都必须对参数进行 URL 编码。
-
推荐工具:
- iOS: 使用
URLComponents,它提供了最安全、最现代的方式来构建 URL,会自动处理所有编码细节。 - Android: 使用
Uri.Builder,它的appendQueryParameter方法会自动编码。 - Web (JavaScript): 使用
encodeURIComponent(),注意要对每个参数值单独编码。
- iOS: 使用
-
解码责任:编码的责任在发送方,解码的责任在接收方,接收方使用系统提供的方法(如
URLComponents.queryItems或Uri.getQueryParameter)获取到的值已经是解码后的原始字符串,无需再手动解码。 -
避免误区:
- 不要用
Base64:虽然 Base64 可以把二进制转成文本,但它不是为 URL 设计的,, , 等字符在 URL 中有特殊含义,也需要额外处理,反而更麻烦。 - 不要手动替换:比如把空格换成 ,把 换成
%23等,这种做法不全面且容易出错,应该交给标准的 URL 编码库/函数来完成。
- 不要用
遵循以上原则,你就可以在各种场景下稳定、可靠地使用中文参数进行 openURL 跳转了。
