[NSURL URLWithString:urlString]默认实现逻辑变动

[NSURL URLWithString:urlString]以前的逻辑是urlString有中文字符就返回nil,现在是默认对非法字符(包含中文)进行%转义。

URLWithString:办法并没有给出说明,但是iOS17新增了URLWithString:encodingInvalidCharacters:办法,详细能够参照此办法。

/// Initializes and returns a newly created `NSURL` with a URL string and the option to add (or skip) IDNA- and percent-encoding of invalid characters.
/// If `encodingInvalidCharacters` is false, and the URL string is invalid according to RFC 3986, `nil` is returned.
/// If `encodingInvalidCharacters` is true, `NSURL` will try to encode the string to create a valid URL.
/// If the URL string is still invalid after encoding, `nil` is returned.
///
/// - Parameter URLString: The URL string.
/// - Parameter encodingInvalidCharacters: True if `NSURL` should try to encode an invalid URL string, false otherwise.
/// - Returns: An `NSURL` instance for a valid URL, or `nil` if the URL is invalid.
+ (nullable instancetype)URLWithString:(NSString *)URLString encodingInvalidCharacters:(BOOL)encodingInvalidCharacters API_AVAILABLE(macos(14.0), ios(17.0), watchos(10.0), tvos(17.0));

附带的BUG

这一个改动原本没有什么大问题,但问题是有BUG。

假如urlString中没有中文,那urlString里原有的%字符不会转义。

(lldb) po [NSURL URLWithString:@"http://a.com?redirectUri=http%3A%2F%2Fb.com"]
http://a.com?redirectUri=http%3A%2F%2Fb.com

假如urlString中有中文字符,那么中文字符和%字符都会被转义,最终会影响运行作用。

(我便是由于这个BUG,从而导致原本能正常进行302重定向的页面无法重定向。)

(lldb) po [NSURL URLWithString:@"http://a.com?title=标题&redirectUri=http%3A%2F%2Fb.com"]
http://a.com?title=%E6%A0%87%E9%A2%98&redirectUri=http%253A%252F%252Fb.com

修正方案

对原办法进行替换,确保[NSURL URLWithString:urlString]在iOS17体系上的运行逻辑和iOS17以下体系保持一致。这样关于现有代码逻辑的影响最小。

#import "NSURL+iOS17.h"
@implementation NSURL (iOS17)
+(void)load {
    [self sv_swizzleClassMethod:@selector(URLWithString:) withClassMethod:@selector(wt_URLWithString:) error:NULL];
}
+ (instancetype)wt_URLWithString:(NSString *)URLString {
    if (@available(iOS 17.0, *)) {
        return [self URLWithString:URLString encodingInvalidCharacters:NO];
    } else {
        return [self wt_URLWithString:URLString];
    }
}
@end