1

My project developing by Delphi XE7 for Androiod device need the function declared in the title.

I found a piece of code which can run and get the correct results on Windows and IOS platform. But on an Android device, the results are always: IP address = 127.0.0.1, subnet mask is blank.

procedure TForm1.RefreshList;
var
  LList: TIdStackLocalAddressList;
  I: Integer;
  AAddresses: TStrings;
begin
  AAddresses := TStringList.Create;
  try
    TIdStack.IncUsage;
    try
      LList := TIdStackLocalAddressList.Create;
      try
        // for backwards compatibility, return only IPv4 addresses
        GStack.GetLocalAddressList(LList);
        if LList.Count > 0 then begin
          AAddresses.BeginUpdate;
          try
            for I := 0 to LList.Count-1 do begin
              if LList[I].IPVersion = Id_IPv4 then begin
                AAddresses.Add(
                  LList[I].IPAddress+':'+
                  TIdStackLocalAddressIPv4(LList[I]).SubNetMask);
              end;
            end;
          finally
            AAddresses.EndUpdate;
          end;
        end;
      finally
        LList.Free;
      end;
    finally
      TIdStack.DecUsage;
    end;
    if AAddresses.Count > 0 then
      Text1.Text:= AAddresses.Text;
  finally
    AAddresses.Free;
  end;
end;

I found that by android.net.wifi.WifiManager.getDhcpInfo can probably get the information, but I do not know how to use the interface in Delphi or is that the right way?

mjn
  • 36,362
  • 28
  • 176
  • 378
photarys
  • 31
  • 1
  • 5
  • 1
    The `SubNetMask` property is not implemented on Android yet. The `IPAddress` is `127.0.0.1` because Indy resorts to using `getaddrinfo()` on Android, specifying the local hostname as the host to resolve, and apparently Android resolves it to the loopback IP. On OSX/iOS, Indy uses the POSIX `getifaddrs()` function, and on Windows it uses the Win32 `GetAdaptersInfo()`/`GetAdaptersAddresses()` functions. Those APIs report actual IPs and subnet masks... – Remy Lebeau Jun 29 '15 at 18:52
  • ... Indy has a TODO item for supporting `getifaddrs()` on Android (which is not natively supported by Android, but there is a third-party implementation floating around) or native Android APIs via Delphi's JNI bridge framework (but that does not solve the problem for FreePascal, though, so `getifaddrs()` would be needed for that). – Remy Lebeau Jun 29 '15 at 18:53
  • @Remy I still have this problem, on Delphi 10 Seattle. No matter what I try, `TIdStack`, `TIdTCPClient` `.Socket.BoundIP`, or the `JNI`. No matter what I try, I always get `127.0.0.1`. Quite frustrating I still haven't found a solution :-/ – Jerry Dodge Sep 18 '17 at 15:58
  • @JerryDodge Indy hasn't been updated yet to address this issue on Android. Note that `BoundIP` is an input-only property, not an output property. If you want the IP bound to, use `TIdTCPClient.Socket.Binding.IP` after connecting. Otherwise, using the JNI bridge to access Java APIs should be able to get the correct IP provided you are using the API correctly to begin with. Feel free to post a new question about that. – Remy Lebeau Sep 18 '17 at 16:05

1 Answers1

0
type

  JWifiManager = interface;
  JDhcpInfo = interface;

  JWifiManagerClass = interface( JObjectClass )
    ['{0238345B-CF08-4139-B943-64900FC845F5}']
    function _GetACTION_PICK_WIFI_NETWORK : JString;
    function _GetEXTRA_WIFI_INFO : JString;
    function _GetWIFI_STATE_CHANGED_ACTION : JString;

    property ACTION_PICK_WIFI_NETWORK : JString read _GetACTION_PICK_WIFI_NETWORK;
    property EXTRA_WIFI_INFO : JString read _GetEXTRA_WIFI_INFO;
    property WIFI_STATE_CHANGED_ACTION : JString read _GetWIFI_STATE_CHANGED_ACTION;
  end;

  [ JavaSignature( 'android/net/wifi/WifiManager' ) ]
  JWifiManager = interface( JObject )
    ['{28DF429C-6E3E-4AFE-8372-18D8E81734E4}']
    function isWifiEnabled : Boolean; cdecl;
    function setWifiEnabled( enabled : Boolean ) : Boolean; cdecl;
    function getDhcpInfo : JDHCPInfo; cdecl;
    function getWifiState : Integer; cdecl;
    function getConnectionInfo : JWifiInfo; cdecl;
  end;

  TJWifiManager = class( TJavaGenericImport< JWifiManagerClass, JWifiManager > )
  end;


  JDHCPInfoClass = interface( JObjectClass )
    [ '{65204FA7-CD50-4EA9-85D6-0A9296A01C40}' ]
  end;

  [ JavaSignature( 'android/net/DhcpInfo' ) ]
  JDHCPInfo = interface( JObject )
    [ '{BBA64EF4-C771-4ECE-BD98-D6A706A5137F}' ]
  end;

  TJDHCPInfo = class( TJavaGenericImport< JDHCPInfoClass, JDHCPInfo > )
  end;


procedure TForm1.Button1Click(Sender: TObject);
var
  WifiManagerObj: JObject;
  WifiManager: JWifiManager;
  DhcpInfo: JDHCPInfo;
begin
  WifiManagerObj := SharedActivityContext.getSystemService(TJContext.JavaClass.WIFI_SERVICE);
  WifiManager := TJWifiManager.Wrap((WifiManagerObj as ILocalObject).GetObjectID);
  try
    DhcpInfo:= WifiManager.getDhcpInfo;
    text1.Text:= Text1.Text + #13#13 + JStringToString(DhcpInfo.toString);
  except on E:System.SysUtils.Exception do
    begin
      text1.Text:= e.ToString;
    end;
  end;
end;

the code above can print out right information in string format. Any suggestions about define the JDHCPInfoClass and JDHCPInfo interface to read field value directly? such as : DhcpInfo.netmask, DhcpInfo.gateway ?

photarys
  • 31
  • 1
  • 5
  • Note that this approach only works when connected to a WiFi network, but not to a cellular network. For that, you have to enumerate the lists returned by the `getNetworkInterfaces()` and `getInetAddresses()` methods of Android's [`NetworkInterface`](https://developer.android.com/reference/java/net/NetworkInterface.html) class – Remy Lebeau Sep 18 '17 at 16:13