Modeled on @Remy Lebeau's very helpful code example in this SO item, I have the below function, which works as expected in Windows 10 to return; e.g.:
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
But when I change the platform to Android 64-bit and run it on my Samsung S21 while WiFi is enabled and connected to my LAN, it returns only the local loopback IP and none of the other values; e.g.:
No of Addresses: 1
IPv4 Addresses:
IP Address #0: 127.0.0.1 - - 0
IP: 127.0.0.1
I had hoped that this had to do with lack of some permission, but as Remy points out in a comment, the problem is that the Indy10 method is broken for Android and one needs to use Dave Nottage's workaround below. (If you want also to get the NetMask that the Indy method is supposed to return, you'll need further work. If/when I get this doped out, I'll post my solution as an answer here)
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;
CodePudding user response:
As per this gist but repeated here:
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;
Use at your own risk