加载页面后无法在 UIWebview 中更改 UserAgent

Can't change UserAgent in UIWebview after loading page

我的 IOS 应用程序中有几个 UIWebView。有时,用户可能需要从移动站点更改为任何给定 URL 的桌面站点。我正在使用欺骗通过更改 UserAgent 来做到这一点:

 + (void) startSpoofingUserAgent
 {
     [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent" : @"Desktop" }];
     [[NSUserDefaults standardUserDefaults] synchronize];
 }

我还有一个杀毒方法:

 + (void)stopSpoofingUserAgent
 {
      NSDictionary *registeredDefaults = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSRegistrationDomain];
      if ([registeredDefaults objectForKey:@"UserAgent"] != nil)
      {
          NSMutableDictionary *mutableCopy = [NSMutableDictionary dictionaryWithDictionary:registeredDefaults];
          [mutableCopy removeObjectForKey:@"UserAgent"];
          [[NSUserDefaults standardUserDefaults] setVolatileDomain:mutableCopy forName:NSRegistrationDomain];
          [[NSUserDefaults standardUserDefaults] synchronize];
      }
}

然后我让用户能够通过一个按钮从桌面切换到移动以及从移动切换到桌面。然后我用这个代码重新加载 URL:

        self.webView.delegate = self;
        self.webView.scalesPageToFit = YES;
        self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

        //Create a URL object.
        NSURL *url = [NSURL URLWithString:self.convertedURL];

        //URL Request Object
        if(self.defaultToDesktopSite)
        {
            [MINNetworkingUtils startSpoofingUserAgent];
        }
        else
        {
            [MINNetworkingUtils stopSpoofingUserAgent];
        }

        NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

        //Load the request in the UIWebView.
        [self.webView loadRequest:requestObj];

我还缓冲了用户拥有 UIWebView 的当前状态,以便它保留跨实例的设置。应用程序第一次运行时,无论它处于哪种状态(桌面或移动),它都能很好地运行。

问题: 问题是我无法更改状态并在初始加载后将其反映在应用程序中。

场景 1:

场景 2:

场景 3:

场景 4:

似乎正在发生的事情是,UIWebView 正在某处缓冲某些内容,不允许我使用不同的欺骗重新加载 UIWebView。如果卸载并重新加载应用程序,UIWebView 将按预期工作。

我尝试了以下方法来强制 UIWebView 不缓冲任何内容,但没有成功:

 [[NSURLCache sharedURLCache] removeAllCachedResponses];
 ... reload URL

  self.convertedPageURL = [NSString stringWithFormat:@"%@?t=%@", self.convertedPageURL, randomString];
  ... reload URL

就像我说的,如果不卸载应用程序并重新加载它,我无法让 UIWebView 从桌面到移动或移动到桌面更改。

求助!!!

编辑

这是我用来获取当前值的代码。一旦我调用了这行代码,我就不能再更改 UserAgent:

         defaultUserAgentString = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];

UserAgent user-defaults 密钥是私有的 API。因此,它没有保证的行为。所有答案都将是经验性的。

话虽如此,听起来正确的解决方案是在每次更改后终止并重新创建 UIWebViewUIView 不符合 NSCopying 因此您需要手动执行一些操作,例如:

UIWebView *newWebView = [[UIWebView alloc] initWithFrame:self.webView.frame];
newWebView.delegate = self;
newWebView.scalesPageToFit = YES;
// ... and the autoreseizing mask, etc — no need to do this upon every load

[self.webView.superview insertSubview:newWebView aboveSubview:self.webView];
[self.webView removeFromSuperview];
self.webView = newWebView;

如果这不起作用,您可能需要切换到已记录的设置用户代理的方法。我建议实施您自己的 NSURLProtocol 处理程序,该处理程序接受尚未看到的 httphttps 请求,修改 header 字段并再次发送它们,即时间拒绝接受他们,以便他们下降到系统。这会很麻烦,但它允许您更改该字段或任何其他 header 字段,可靠且立即生效。

有关示例,请参阅 kifi's engineering blog