在實現客戶端集成微博登錄功能時,點擊通過新浪微博登錄
按鈕,此時
- 假如設備上已經安裝微博客戶端,會跳轉到微博客戶端進行授權登錄
- 假如設備上尚無安裝微博客戶端,會在當前客戶端中彈出微博的網頁登錄授權界面
在沒有安裝微博客戶端的情況中,加載網頁時出現了下圖中的 UI 展示 BUG:藍色進度條位置不對(原因后面會介紹)。
藍色進度條的位置很尷尬
仔細看了一下項目中的邏輯,確定不是自己的代碼問題之后,開始檢查是否是 WeiBoSDK
中的問題。WeiBoSDK
不開源,不過我們可以用第三方輔助開發工具 Reveal
試著檢查一下 WeiBoSDK
中的界面元素:
通過 Reveal 檢查出現 Bug 的界面
通過 Reveal
的分析,發現這個進度條在其 superView
的 Y
方向向下偏移 64 個點,比較敏感的開發者這時候應該能察覺出來的這一 BUG 可能與狀態欄和導航欄有一定關系(在 iOS 中,statusBar.height + navigationBar.height = 64
)。在當前開發的客戶端中,presentingViewController
(即彈出微博登錄頁面之前的那個 VC
)是沒有導航欄的。
出現這種情況,可以通過Objective-C runtime
機制糾正一下進度條的垂直位置。
在項目工程中新建一個category
: UIViewController+TWWBWebViewFix
,這里的頭文件中沒有代碼邏輯,下面展示出實現文件中的完整代碼:
#import "UIViewController+TWWBWebViewFix.h"
#import <objc/runtime.h>
@implementation UIViewController (TWWBWebViewFix)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// When swizzling a class method, use the following:
// 'Class class = object_getClass((id)self);'
// or 'Class class = object_getClass([self class]);'
// Here swizzling a instance method:
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(TW_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// 先嘗試給源方法添加實現,這里是為了避免源方法沒有實現的情況
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
// 添加成功:將源方法的實現替換到交換方法的實現
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
// 添加失敗:說明源方法已經有實現,直接將兩個方法的實現交換即可
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (void)TW_viewWillAppear:(BOOL)animated {
[self TW_viewWillAppear:animated];
// 下面代碼中的字符串所對應的類可以查看文末圖片給出的信息
if ([self isKindOfClass:NSClassFromString(@"WBSDKAuthorizeWebViewController")]) {
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:NSClassFromString(@"WBSDKWebView")]) {
for (UIView *subView in view.subviews) {
if ([subView isKindOfClass:NSClassFromString(@"WBSDKWebViewProgressView")]) {
subView.frame = CGRectMake(0, 0, kDeviceWidth, 3);
}
}
}
}
}
}
@end
在 Reveal 中檢查 V 與 C 對應關系