修复CodeTyphon在Android P下的请求失败问题

CodeTyphon 提供了一种非常方便的网络访问方式,这在 JNI 内尤其有用,代码如下:

with TFPHttpClient.Create(nil) do begin
    Result := Get(URL);
    Free;
end;

如果希望使用异步的方式,并且更加方便的进行 Post 请求或是上传文件,可以使用我封装好的库,点击此处看项目:

with THttpThread.Create(URL, hmPost) do begin
    PostParam.Add('key', 'value');
    FileParam.Add('file', '/sdcard/sample.txt');
    Callback := @httpCallback
    Start();
end;

然而,在 Android P上,这样的代码会报一个异常,无法正常发起请求,经过跟踪,发现请求时未发现 DNS Server,因此无法对域名进行解析,造成请求失败。

看一下 CodeTyphon 内的 fpcsrc,可以找到 fcl-net 下有一个 netdb.pp 文件,里面针对 Android 的处理有一段关键代码:

{$ifdef android}
Function GetDNSServers: Integer;
var
    i: integer;
    s: string;
    H: THostAddr;
begin
    Result := 0;
    SetLength(DNSServers, 9);
    for i := 1 to 9 do begin
        s := GetSystemProperty(PAnsiChar('net.dns' + IntToStr(i)));
        if s = '' then break;
        H := StrToNetAddr(s);
        if H.s_bytes[1] <> 0 then begin
            DNSServers[Result] := H;
            Inc(Result);
        end;
    end;
    SetLength(DNSServers, Result);
end;

其实已经很明显能看到问题了,由于 Android P 不再允许使用 net.dnsX 来获取 DNS Server,因此这段代码将返回 Permission Denied 并且使 s 的值永久为空。

既然无法突破 Google 的限制,那就给设定一个默认的 DNS Server 来解决问题了,在不破坏原有逻辑的前提下,增加一些代码:

{$ifdef android}
Function GetDNSServers: Integer;
var
    i: integer;
    s: string;
    H: THostAddr;
begin
    Result := 0;
    SetLength(DNSServers, 9);
    for i := 1 to 9 do begin
        s := GetSystemProperty(PAnsiChar('net.dns' + IntToStr(i)));
        if s = '' then break;
        H := StrToNetAddr(s);
        if H.s_bytes[1] <> 0 then begin
            DNSServers[Result] := H;
            Inc(Result);
        end;
    end;

    // fix
    if (Result = 0) then begin
        H := StrToNetAddr('8.8.8.8');
        DNSServers[0] := H;
        Inc(Result);
    end;

    SetLength(DNSServers, Result);
end;

经过测试,这段代码在 Android P 上能够正常工作,至此,问题修复完毕。

相关的 fix 代码也已上传至 CodeTyphon 官方论坛,将在下个版本被合并,点击此处查看官方论坛帖子

你可能感兴趣的:(修复CodeTyphon在Android P下的请求失败问题)