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 官方论坛,将在下个版本被合并,点击此处查看官方论坛帖子