如何让TIdStackLocalAddress在Android上工作?

6xfqseft  于 2022-10-16  发布在  Android
关注(0)|答案(2)|浏览(221)

仿照@Remy Lebeauthis SO item中非常有用的代码示例,我有以下函数,它在Windows 10中按预期工作以返回;例如:

No of Addresses: 4
  IPv4 Addresses:
  IP Address #0: 192.168.56.1 - 255.255.255.0 - 11
  IP Address #1: 192.168.1.7 - 255.255.255.0 - 8
  IP: 192.168.56.1

但是,当我将平台更改为Android 64位并在我的Samsung S21上运行时,同时启用WiFi并连接到我的局域网,它只返回本地环回IP,而不返回任何其他值;例如:

No of Addresses: 1
IPv4 Addresses:
IP Address #0: 127.0.0.1 -  - 0
IP: 127.0.0.1

我曾希望这与缺乏一些许可有关,但正如雷米在一条评论中指出的那样,问题是Indy10方法在Android上是错误的,人们需要使用Dave Notage下面的解决方案。如果您还想获得Indy方法应该返回的NetMASK,您可以使用下面发布的我的解决方案作为答案。

function getLocalIP: string;
begin
  Result := '';
  try
    var IPList := TIdStackLocalAddressList.Create;
    try
      TIdStack.IncUsage;
      try
        GStack.GetLocalAddressList(IPList);
      finally
        TIdStack.DecUsage;
      end;

      WriteLog('DEBUG', 'No of Addresses: ' + IntToStr(IPList.Count));
      WriteLog('DEBUG', 'IPv4 Addresses:');

      var IPStrings := TStringList.Create;
      try
        for var i in IPList do
        begin
          if TIdStackLocalAddressIPv4(i).IPVersion = Id_IPv4 then
          begin
            IPStrings.Add(TIdStackLocalAddressIPv4(i).IPAddress + ' - ' + TIdStackLocalAddressIPv4(i).SubNetMask
              + ' - ' + TIdStackLocalAddressIPv4(i).InterfaceIndex.ToString);
          end;
        end;

        // show IP Addresses in the log file
        for var i := 0 to IPStrings.Count-1 do
          WriteLog('DEBUG', 'IP Address #' + IntToStr(i) + ': ' + IPStrings[i]);
        Result := IPStrings[0].Split([' - '])[0];
        WriteLog('DEBUG', 'IP: ' + Result);
      finally
        IPStrings.Free;
      end;
    finally
      IPList.Free;
    end;
  except
    On E: Exception do
    begin
      Result := '';
      WriteLog('ERROR', 'IP Error: ' + E.message);
    end;
  end;
end;
knpiaxh1

knpiaxh11#

根据this gist,但在此重复:

interface

uses
  IdStack;

procedure GetLocalAddressList(const AAddresses: TIdStackLocalAddressList);

implementation

uses
  System.SysUtils,
  Androidapi.JNI.Java.Net, Androidapi.JNI.JavaTypes, Androidapi.Helpers,  Androidapi.JNIBridge,
  IdGlobal;

procedure GetLocalAddressList(const AAddresses: TIdStackLocalAddressList);
var
  LInterfaces, LAddresses: JEnumeration;
  LInterface: JNetworkInterface;
  LAddress: JInetAddress;
  LInet4Address: JInet4Address;
  LInet6Address: JInet6Address;
  LName, LHostAddress: string;
begin
  AAddresses.Clear;
  LInterfaces := TJNetworkInterface.JavaClass.getNetworkInterfaces;
  while LInterfaces.hasMoreElements do
  begin
    LInterface := TJNetworkInterface.Wrap(JObjectToID(LInterfaces.nextElement));
    LAddresses := LInterface.getInetAddresses;
    while LAddresses.hasMoreElements do
    begin
      LAddress := TJInetAddress.Wrap(JObjectToID(LAddresses.nextElement));
      if LAddress.isLoopbackAddress then
        Continue;
      // Hack until I can find out how to check properly
      LName := JStringToString(LAddress.getClass.getName);
      LHostAddress := JStringToString(LAddress.getHostAddress);
      // Trim excess stuff
      if LHostAddress.IndexOf('%') > -1 then
        LHostAddress := LHostAddress.Substring(0, LHostAddress.IndexOf('%'));
      if LName.Contains('Inet4Address') then
        TIdStackLocalAddressIPv4.Create(AAddresses, LHostAddress, '')
      else if LName.Contains('Inet6Address') then
        TIdStackLocalAddressIPv6.Create(AAddresses, LHostAddress);
    end;
  end;
end;

使用风险自负

wecizke3

wecizke32#

以下是我根据@Dave Notage的要点想出的检索Android IPv4地址和子网掩码的方法:

unit AndroidGetInetAddress;

interface

{$IFDEF Android}
uses
  System.SysUtils, {System.Types, System.UITypes, System.Classes, System.Variants,}
  IdStack{, IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient, IdGlobal};

procedure GetLocalAddressList(const AAddresses: TIdStackLocalAddressList);
{$ENDIF}

implementation

{$IFDEF Android}

uses
  Androidapi.JNI.Java.Net, Androidapi.JNI.JavaTypes, Androidapi.Helpers,  Androidapi.JNIBridge;

{ Dumb conversion of number of bits to 4-byte SubnetMask string}
function SubnetMask(ACode: string): string;
begin
  var NCode := ACode.ToInteger;
  if NCode < 25 then
    Result := '255.255.255.' + (%11111111 shr NCode).ToString
  else if NCode < 33 then
    Result := '255.255.' + (%11111111 shr NCode-24).ToString + '.0'
  else if NCode < 41 then
    Result := '255.' + (%11111111 shr NCode-32).ToString + '.0.0'
  else if NCode < 49 then
    Result := (%11111111 shr NCode-40).ToString + '.0.0.0'
  else
    Result := '0.0.0.0.';
end;

procedure GetLocalAddressList(const AAddresses: TIdStackLocalAddressList);

begin
  AAddresses.Clear;
  var LInterfaces := TJNetworkInterface.JavaClass.getNetworkInterfaces;

  while LInterfaces.hasMoreElements do
  begin
    var LInterface := TJNetworkInterface.Wrap(TAndroidHelper.JObjectToID(LInterfaces.nextElement));

////// method getInetAddresses evidently does not return a subnet mask
//    var LAddresses := LInterface.getInetAddresses;
//    while LAddresses.hasMoreElements do
//    begin
//      var LAddress := TJInetAddress.Wrap(TAndroidHelper.JObjectToID(LAddresses.nextElement));
//      WriteLog('DEBUG', 'getAddress: ' + JStringToString(LAddress.ToString));
//      if LAddress.isLoopbackAddress then
//        Continue;
//      // Dave Nottage: Hack until I can find out how to check properly
//      WriteLog('DEBUG', 'LName: ' + JStringToString(LAddress.getClass.getName));
//      WriteLog('DEBUG', 'LHostAddress: ' + JStringToString(LAddress.getHostAddress));
//    end;

////// method getInterfaceAddresses does return IP address, mask, and '[null]' or broadcast IP
    var LInterfaceAddresses := LInterface.getInterfaceAddresses;
    for var i := 0 to LInterfaceAddresses.size-1 do
    begin
      var LHostAddress := JStringToString(LInterfaceAddresses.get(i).toString);
//      WriteLog('DEBUG', 'Address ' + i.ToString + ': ' + LHostAddress);
      if not LHostAddress.Contains('[null]') then
      // Have IPv4Inet address with subnet mask and broadcast address
      begin
        var Address := LHostAddress.Split(['/','[',']',' '], TStringSplitOptions.ExcludeEmpty);
        TIdStackLocalAddressIPv4.Create(AAddresses, Address[0], SubnetMask(Address[1]))
      end;
    end;
  end;
end;
{$ENDIF}

end.

“使用风险自负”:)

相关问题