mPaas基线升级到 10.1.68-beta(9)之后-setTitleViewTitle:只会走一次的问题原因分析

 

1.打断点查看setTitleViewTitle调用堆栈

发现是调用的__NSThreadPerformPerform

 

2.上hopper查找调用setTitleViewTitle所在类

0000000102aad358         dq         0x1020a9341                                 ; @selector(setTitleViewTitle:), "setTitleViewTitle:", DATA XREF=

-[Plugin4HandleProxyRequest handleEvent:]+2452,

-[Plugin4HandleProxyRequest handleEvent:]+3108, ___60

-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke+288,

-[TAComponentWebview observeValueForKeyPath:ofObject:change:context:]+301,

-[TAComponentWebview observeValueForKeyPath:ofObject:change:context:]+375

 

3这样好麻烦

直接把这个方法替换成别的吧

[rbx performSelectorOnMainThread:@selector(setTitleViewTitle:) withObject:var_-80 waitUntilDone:0x0];

 

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSThread (YYY)

@end

NS_ASSUME_NONNULL_END



#import "NSThread+YYY.h"
#import <objc/runtime.h>

@implementation NSThread (YYY)
+(void)load{
    {
         Method originalMethod = class_getInstanceMethod([NSThread class], @selector( performSelectorOnMainThread:withObject:waitUntilDone:));
         Method swizzledMethod = class_getInstanceMethod([NSThread class], @selector( performSelectorOnMainThread:withObject:waitUntilDoneS:));
            method_exchangeImplementations(originalMethod, swizzledMethod);
         
    }
}
-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDoneS:(BOOL)wait{
    if ([self isKindOfClass:[NSClassFromString(@"UIKeyboardTaskQueue")  class]]) {
        [self performSelectorOnMainThread:aSelector withObject:arg waitUntilDoneS:wait];
        return;
    }
    
    NSLog(@"^^^^^^##### %@ %@ %@",self,NSStringFromSelector(aSelector),arg);
}
@end

打印需要的信息

--[NSThread(YYY) performSelectorOnMainThread:withObject:waitUntilDoneS:]-^^^^^^##### <ViewController: 0x7f968f9dca00> setTitleViewTitle: XXXXXXXX-

看到堆栈为

 

对比基线升级之前的工程堆栈(每次都会调用)

 

 

5.查看升级提示 

mPaaS 10.1.68 发布说明

从 10.1.68 基线开始正式废弃 UIWebView,只支持 WKWebView,详情可参考 mPaaS 适配 WKWebView。由于 App Store 从 2020 年 4 月起不再接受使用 UIWebView 的新 APP,从 2020 年 12 月起不再接受使用 UIWebview 的 APP 的更新,详情请参见 苹果官方声明 。请 2020 年 4 月前仍未上架 APP Store 的新应用,尽快升级适配 WKWebView。

 

原因猜测 换了wk 异步回调导致

 

6.看看新工程有没有每次调用-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]

经验证新工程每次都会调用

 

7.看一下新工程-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]伪源码

void -[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:](void * self, void * _cmd, void * arg2, void * arg3) {
    var_-48 = [arg2 retain];
    rax = [arg3 retain];
    r14 = [[rax request] retain];
    var_-56 = rax;
    r13 = [[rax response] retain];
    rbx = [[r14 mainDocumentURL] retain];
    r15 = r14;
    rax = [r14 URL];
    rax = [rax retain];
    r14 = rax;
    rax = [rbx isEqual:rax];
    var_-80 = r13;
    if (rax != 0x0) {
            r12 = [r13 statusCode];
            [r14 release];
            [rbx release];
            r13 = r15;
            if (r12 == 0xc8) {
                    rax = [H5Configs sharedConfigs];
                    rax = [rax retain];
                    var_-72 = rax;
                    r12 = [[rax titleReg] retain];
                    var_-64 = [var_-48 length];
                    var_-128 = __NSConcreteStackBlock;
                    *(&var_-128 + 0x8) = 0xc2000000;
                    *(&var_-128 + 0x10) = ___60-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke;
                    *(&var_-128 + 0x18) = ___block_descriptor_48_e8_32s40s_e37_v32?0"NSTextCheckingResult"8Q16^B24l;
                    rax = [var_-48 retain];
                    *(&var_-128 + 0x20) = rax;
                    *(&var_-128 + 0x28) = [var_-56 retain];
                    stack[2048] = &var_-128;
//下面的block var_-64就是上面声明的block ___60
                    [r12 enumerateMatchesInString:rax options:0x0 range:0x0 usingBlock:var_-64];
                    [r12 release];
                    [var_-72 release];
                    [*(&var_-128 + 0x28) release];
                    [*(&var_-128 + 0x20) release];
            }
    }
    else {
            [r14 release];
            [rbx release];
            r13 = r15;
    }
    [var_-80 release];
    [r13 release];
    [var_-56 release];
    [var_-48 release];
    return;
}



function ___60-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke {
    rbx = rcx;
    r14 = rdi;
    rax = [rsi retain];
    r13 = rax;
    if ([rax numberOfRanges] >= 0x2) {
            var_-56 = rbx;
            rax = [r13 rangeAtIndex:0x1];
            rax = [*(r14 + 0x20) substringWithRange:rax];
            rax = [rax retain];
            rbx = rax;
            rax = [rax gtm_stringByUnescapingFromHTML_mp];
            rax = [rax retain];
            var_-48 = r14;
            r14 = rax;
            [rbx release];
            rax = [NSCharacterSet whitespaceAndNewlineCharacterSet];
            rax = [rax retain];
            r12 = [[r14 stringByTrimmingCharactersInSet:rax] retain];
            [r14 release];
            [rax release];
            rax = [*(var_-48 + 0x28) context];
            rax = [rax retain];
            r14 = rax;
            rax = [rax currentViewController];
            rax = [rax retain];
            [rax performSelectorOnMainThread:@selector(setTitleViewTitle:) withObject:r12 waitUntilDone:0x0];
            rbx = var_-56;
            [rax release];
            [r14 release];
            [r12 release];
    }
    *(int8_t *)rbx = 0x1;
    rax = [r13 release];
    return rax;
}

8再看看旧工程伪源码

void -[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:](void * self, void * _cmd, void * arg2, void * arg3) {
    var_-48 = [arg2 retain];
    rbx = [arg3 retain];
    r14 = [[rbx request] retain];
    var_-56 = rbx;
    r13 = [[rbx response] retain];
    rbx = [[r14 mainDocumentURL] retain];
    r15 = r14;
    r14 = [[r14 URL] retain];
    rax = [rbx isEqual:r14];
    var_-80 = r13;
    if (rax != 0x0) {
            r12 = [r13 statusCode];
            [r14 release];
            [rbx release];
            r13 = r15;
            if (r12 == 0xc8) {
                    rax = [H5Configs sharedConfigs];
                    rax = [rax retain];
                    var_-72 = rax;
                    r12 = [[rax titleReg] retain];
                    rax = [var_-48 length];
                    var_-128 = __NSConcreteStackBlock;
                    *(&var_-128 + 0x8) = 0xc2000000;
                    *(&var_-128 + 0x10) = ___60-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke;
                    *(&var_-128 + 0x18) = ___block_descriptor_tmp.890;
                    rbx = [var_-48 retain];
                    *(&var_-128 + 0x20) = rbx;
                    *(&var_-128 + 0x28) = [var_-56 retain];
                    stack[2048] = &var_-128;
                    [r12 enumerateMatchesInString:rbx options:0x0 range:0x0 usingBlock:rax];
                    [r12 release];
                    [var_-72 release];
                    [*(&var_-128 + 0x28) release];
                    [*(&var_-128 + 0x20) release];
            }
    }
    else {
            [r14 release];
            [rbx release];
            r13 = r15;
    }
    [var_-80 release];
    [r13 release];
    [var_-56 release];
    [var_-48 release];
    return;
}

function ___60-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke {
    rbx = rcx;
    r14 = rdi;
    r13 = [rsi retain];
    if ([r13 numberOfRanges] >= 0x2) {
            var_-56 = rbx;
            var_-48 = r14;
            rbx = [[*(r14 + 0x20) substringWithRange:[r13 rangeAtIndex:0x1]] retain];
            r14 = [[rbx gtm_stringByUnescapingFromHTML_mp] retain];
            [rbx release];
            rbx = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
            r12 = [[r14 stringByTrimmingCharactersInSet:rbx] retain];
            [r14 release];
            [rbx release];
            r14 = [[*(var_-48 + 0x28) context] retain];
            rbx = [[r14 currentViewController] retain];
            [rbx performSelectorOnMainThread:@selector(setTitleViewTitle:) withObject:r12 waitUntilDone:0x0];
            rdi = rbx;
            rbx = var_-56;
            [rdi release];
            [r14 release];
            [r12 release];
    }
    *(int8_t *)rbx = 0x1;
    rax = [r13 release];
    return rax;
}

9通过比较代码是一样的。

 

10.多次比较发现, 没有标题的同时这个block也不会走-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]_block_invoke

no!会走

断点要打在-[NSSimpleRegularExpressionCheckingResult numberOfRanges]

而不是-[NSTextCheckingResult numberOfRanges]

 

11.基线升级前的工程打印

[NSSimpleRegularExpressionCheckingResult(PC) numberOfRangesS]-!!!!!!!<NSSimpleRegularExpressionCheckingResult: 0x600002ea71c0>{1760, 19}{

<NSRegularExpression: 0x6000035bacd0> <title>([\s\S]*?)</title> 0x1}

2

NSTextCheckingResult

self->_regularExpression->_pattern:

<title>([\s\S]*?)</title>

 

12.替换这个方法                   

[r12 enumerateMatchesInString:rbx options:0x0 range:0x0 usingBlock:rax];

并在-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]打断点后再进入enumerateMatchesInString:rbx断点

打印传入的字符串

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport"

是html报文

结合上面的正则  是找title

 

13.查看numberOfRanges注释  上面打印返回值是2

/* A result must have at least one range, but may optionally have more (for 
example, to represent regular expression capture groups).  The range at index 0 
always matches the range property.  Additional ranges, if any, will have indexes 
from 1 to numberOfRanges-1. rangeWithName: can be used with named regular 
expression capture groups. */
@property (readonly) NSUInteger numberOfRanges

 

14.1在基线升级后工程打印 进一步 发现-[Plugin4HandleProxyRequest setNavigateTitleWithHtml:event:]这个没走

所以设置title方法也不会走 ,因为前后点的功能不同。

14.2 走了setNavigateTitleWithHtml:event的方法情况,判断的时候没有title正则,所以也不会继续往下走

 

15.这应该是原有的bug因为不重新指定h5容器也会有这个问题。

 

最后再看看这个规则伪源码:

void * -[H5Configs titleReg](void * self, void * _cmd) {
    r14 = [[*(self + 0x110) stringValueForKey:@"h5_titleRegularExpression"] retain];
    if (([r14 isKindOfClass:[NSString class]] != 0x0) && ([r14 length] != 0x0)) {
            rax = [NSRegularExpression regularExpressionWithPattern:r14 options:0x1 error:0x0];
            rax = [rax retain];
            rbx = rax;
            if (rax == 0x0) {
                    rbx = [[NSRegularExpression regularExpressionWithPattern:@"<title>([\s\S]*?)</title>" options:0x1 error:0x0] retain];
            }
    }
    else {
            rbx = [[NSRegularExpression regularExpressionWithPattern:@"<title>([\s\S]*?)</title>" options:0x1 error:0x0] retain];
    }
    [r14 release];
    rax = [rbx autorelease];
    return rax;
}

 

 

 

另外收获

1.比如替换这个方法会经常崩溃performSelectorOnMainThread:withObject:waitUntilDone:

2.NSTextCheckingResult

3.block伪源码变量分布

4.寄存器是物理设备,是不受大括号的作用域限制的

 

 

 

补充(总结):1.三方h5 setNavigateTitleWithHtml走的情况下:旧版代码有些功能走setTitleViewTitle方法、有些不走,不走原因是加载的html报文里没有<title>标签。

2.三方h5 setNavigateTitleWithHtml不走的情况是因为数据量大didReceiveData需要执行多次

要看-[Plugin4HandleProxyRequest insertJs:]代码逻辑 有点复杂

3.疑惑:蚂蚁的同学为什么要这么写呢?

问题1:如果注释掉了title标签代码也会走<!-- <title>我是标题</title> -->

问题2:有些html页面没有title标签,但会有其他方法设置标题,这个方法就不会走

问题3:为啥数据量大setNavigateTitleWithHtml都不会走

4.解决办法

void * -[H5WebViewController titleLabelValue](void * self, void * _cmd) {
    r12 = self;
    rax = [self navigationItem];
    rax = [rax retain];
    rbx = [[rax titleView] retain];
    rdx = [H5NavigationTitleView class];
    r14 = [rbx isKindOfClass:rdx];
    [rbx release];
    [rax release];
    if (r14 != 0x0) {
            rax = [r12 navigationItem];
            rax = [rax retain];
            r14 = [[rax titleView] retain];
            [rax release];
            rax = [r14 mainTitleLabel];
            rax = [rax retain];
            rbx = [[rax text] retain];
            [rax release];
            [r14 release];
    }
    else {
            rbx = 0x0;
    }
    rax = [rbx autorelease];
    return rax;
}

 

您提到的是文本排版中的几个概念,它们通常与图形设计软件如Adobe InDesign中的选项有关。下面是这些术语的简要说明: 1. 字符间隔(Character Spacing): 这是调整单个字符之间的空间,也称为字间距。在InDesign中,可以通过“Type” > “ Kerning” 来设置。 2. 单词间隔(Word Spacing, Tw): 指的是单词之间的间距,即单词末尾和下一个单词开头之间的空白。在InDesign中,这个设置通常在“Type” > “Tracking” 或者使用快捷键Ctrl+T(Windows/Linux)或Command+T(Mac)来调整。 3. 水平缩放(Horizontal Scaling, Tz): 用于调整文本框相对于页面的比例,它不会改变字符大小,而是改变文本框的尺寸。 4. Leading (Leading, TL): 也叫行距,是指文本行之间的距离,它包括基线基线的距离以及任何额外的行间距。在InDesign中,可以在“Type” > “Line Spacing” 设置。 5. 文本字体(Font, Tf): 选择合适的字体样式、大小和系列是排版的重要部分。在InDesign中,点击“Type” > “Font” 或者直接在工具栏上选择字体并输入大小。 6. 渲染(Render, Tr): 这个术语可能不太准确,可能是指文本的渲染质量或预览效果。在InDesign中,确保文本以适当的分辨率显示,可以在“Output” > “Previews” 中设置。 要具体操作,打开InDesign,选择所需的文本,然后在菜单栏中找到相应的选项进行调整。请注意,每个软件可能有不同的界面和命名方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值