项目中有一套 Router 根据 URL 跳转机制,在实现过程中发现如果 URL 中嵌套另外一个 URL 时,解析会出问题,引起不必要的 bug, 特此记录一下。
一. 设计思路是将嵌套的 URL Encode 之后当做参数传入,解析外层 URL query,这样就可以得到完整的内层 URL。
- 方法一:
NSString *hString = [aString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
这个方法在 iOS 9 之后就被废弃了,但也可以使用,只不过是有警告⚠️。而且对于 URL(例如:http://www.baidu.com?a=b&c=d)中的特殊字符 '&' 不会 encode ,在解析的时候就会出问题。
- 方法二:
NSString *hString = [aString stringByAddingPercentEncodingWithAllowedCharacters: URLHostAllowedCharacterSet];
这个方法中 URLHostAllowedCharacterSet 是官方 API 中给出了几个枚举值:
URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^`
仔细观察就会发现这几个枚举值中的字符集中并没有对 '&' 进行特殊处理,所以就需要自己手动规定需要 encode 的特殊字符集,就像下面这样:
NSString *hString = [aString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!*'();:@&=+ $,./?%#[]"]];
上面这个方法一般的情况可以覆盖到,字符集可以根据自己实际应用情况编写。
- 方法三:
NSString *hString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)subUrl, NULL, (CFStringRef)@"!*'();:@&=+ $,./?%#[]", kCFStringEncodingUTF8));
这个方法就比较简单粗暴了,给定的字符集和汉字都会 encode。
比如 (http://www.baidu.com?a=b&c=d&e=百度)encode 后是 http%3a%2f%2fwww.baidu.com%3fa%3db%26c%3dd%26e%3d%e7%99%be%e5%ba%a6 这样的。但是同样在 iOS 9 之后弃用。
二. 解决了嵌套 URL 的问题,就是解析 URL 了。
比如自己规定的 URL 是这样:
appName://com.appName?a=b&c=d&e=URL // 其中的 URL 就是上面提到了 encode 之后的字符串。
- (NSDictionary *)getUrlParameterWithUrl:(NSURL *)url {
NSMutableDictionary *parm = [[NSMutableDictionary alloc]init];
//传入url创建url组件类
NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithString:url.absoluteString];
//回调遍历所有参数,添加入字典
[urlComponents.queryItems enumerateObjectsUsingBlock:^(NSURLQueryItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[parm setObject:obj.value forKey:obj.name];
}];
return parm;
}
这个方法的好处就是把参数解析出来以后不用对于 encode 了的参数会默认 decode,不需要自己在做任何操作。
这样下来对于项目中使用 URL 跳转页面的需求应该都可以满足了。
网友评论