Jump to content
Guest

Retrieving Android Device IP Address Problem

Recommended Posts

Guest

Porting my 2 applications to Android 13 has taken another turn for the worse.

 

WifiInfo no longer retrieves getIpAddress from an Android device (it gives you a range check error) because it was deprecated in API level 31.  You now have to use LinkProperties.

 

Is there any information out there about using LinkProperties (https://developer.android.com/reference/android/net/LinkProperties) that is useful for non-Java developers?

 

Thanks.

Edited by Guest

Share this post


Link to post
1 hour ago, TazKy said:

Is there any information out there about using LinkProperties (https://developer.android.com/reference/android/net/LinkProperties) that is useful for non-Java developers?

You can use ConnectivityManager.getAllNetworks() to iterate available networks, and ConnectivityManager.getLinkProperties() to get the LinkProperties of each network, for example (yes, it is in Java):

private Network findVpnNetwork() {
  ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  Network[] networks = cm.getAllNetworks();
  for (Network network : networks) {
    LinkProperties linkProperties = cm.getLinkProperties(network);
    List<LinkAddress> addresses = linkProperties.getLinkAddresses();
    for (LinkAddress addr : addresses) {
      if (addr.getAddress().equals(VPN_ADDRESS)) {
        return network;
      }
    }
  }
  return null;
}

So, a Delphi translation to get available IP addresses might look something like this:

function getIpAddresses: TList<JInetAddress>;
begin
  Result := TList<JInetAddress>.Create;
  try
    var svc := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.CONNECTIVITY_SERVICE);
    var cm := TJConnectivityManager.Wrap((svc as ILocalObject).GetObjectID);
    for var network in cm.getAllNetworks do
    begin
      for var addr in cm.getLinkProperties(network).getLinkAddresses do
        Result.Add(addr.getAddress);
    end;
  except
    Result.Free;
    raise;
  end;
end;

 

Edited by Remy Lebeau

Share this post


Link to post
Guest

Hi Remy,

 

Thanks beforehand.

 

I have been able to take your code and it all compiles except for TList<JInetAddress> which is called an "Undeclared identifier: TList<>".  I have added Androidapi.JNI.Java.Net in the uses clause for JInetAddress.  JInetAddress is a JObject.  Cannot figure that one out. Errors are bolded.

 

function getIpAddresses: TList<JInetAddress>;
begin
  Result := TList<JInetAddress>.Create;
  try
    var svc := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.CONNECTIVITY_SERVICE);
    var cm := TJConnectivityManager.Wrap((svc as ILocalObject).GetObjectID);
    for var network in [cm.getAllNetworks] do
    begin
      for var addr in [cm.getLinkProperties(network).getLinkAddresses] do
        Result.Add(addr.getAddress);
    end;
  except
    Result.Free;
    raise;
  end;
end;
 

Edited by Guest

Share this post


Link to post
Guest

Sorry, it did not help.  Just shifted the errors to other areas.

 

Where do I use MyList?

Share this post


Link to post

in fact, many errors occurs on code above... I think that is necessary "review it"... for current IDE's like RAD 11.

 

MyList = my var used to store a list of "TJInetAddress", nothing more.

 

you can use "array", you dont need any TList, at all.

 

Quote

type

   TMyArrOfTJInetAddress = TArray<TJInetAddress>;

....

function xxxx TMyArrOfTJInetAddress;

begin

  result := [ ];

   for ....

   beggin

      //...

      result := result + [   <<your object resulted here >>    ];

   end;

   // ...

end;

 

 

Share this post


Link to post
Guest

I am using 11.3.

 

Since this problem of not being able to read the IP Address from the Android device using Delphi/FireMonkey code since API 31 (which is not that old but still old enough) and basically there is little to no Delphi information on how to read that value, this might be a dead issue, period.

 

Taking programs that were built Android 10 and older and trying to bring them into this "changed" Android arena has been very discouraging.  What was Android thinking???

 

Reading the IP Address automatically was a great benefit in setting both Android apps that communicated with a Windows server.  I guess now the user will have to set the IP Address manually on all programs.

 

I consider this conversation closed.  Thanks for trying to help me.

Share this post


Link to post
5 hours ago, TazKy said:

I have been able to take your code and it all compiles except for TList<JInetAddress> which is called an "Undeclared identifier: TList<>". 

Add the "System.Generics.Collections" unit to your "uses" clause.

https://docwiki.embarcadero.com/Libraries/en/System.Generics.Collections.TList

Quote

I have added Androidapi.JNI.Java.Net in the uses clause for JInetAddress.  JInetAddress is a JObject.  Cannot figure that one out.

I don't write projects for Android.  I didn't say the code would actually compile, but it should give you some ideas of what to look.

Edited by Remy Lebeau

Share this post


Link to post
1 hour ago, TazKy said:

Reading the IP Address automatically was a great benefit in setting both Android apps that communicated with a Windows server.  I guess now the user will have to set the IP Address manually on all programs.

Why do you need to retrieve an Android device's IP address in the first place? What are you planning on doing with it, exactly?

Share this post


Link to post
Guest

We have 2 apps installed on Android devices for barcode reading.  The scanner app scans the barcode and sends the information to the Android server app via UDP.  The Android server app sends/receives information with the Windows server app via TCP/IP.

 

Naturally UDP and TCP/IP require IPA and port number.  The port number is saved (and should not change) but the IPA is read when you start the app.  There are times when you restart the device that the IPA on a device can change.  So having the IPA in your hand reduces possible confusion and the need to save the IPA.

 

These apps are used by our customers and are not available in the app stores.

Edited by Guest

Share this post


Link to post
3 hours ago, TazKy said:

The scanner app scans the barcode and sends the information to the Android server app via UDP.

The scanner app does not need to know the local device IP just to send data to another device.  It only needs to know the receiver's IP.  Probably best to use DNS/mDNS or other local network discovery protocol to discover the receiver's IP dynamically at runtime.

Quote

The Android server app sends/receives information with the Windows server app via TCP/IP.

The Android server app does not need to know the local device IP just to connect to another server. And it does not need to know the local device IP to accept connections, for that matter.

 

So, I'm still wondering why you actually need to query the device IP at all.

Edited by Remy Lebeau

Share this post


Link to post

Is the original question about retrieving local IP addresses? This code still works for me with a target SDK of 31+:

 

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;
  LName, LHostAddress: string;
begin
  AAddresses.Clear;
  LInterfaces := TJNetworkInterface.JavaClass.getNetworkInterfaces;
  while LInterfaces.hasMoreElements do
  begin
    LInterface := TJNetworkInterface.Wrap(LInterfaces.nextElement);
    LAddresses := LInterface.getInetAddresses;
    while LAddresses.hasMoreElements do
    begin
      LAddress := TJInetAddress.Wrap(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;

 

Share this post


Link to post
Guest

Hi Dave,

 

Not sure of how to code your procedure I get some googling and found on StackOverflow "How to make TIdStackLocalAddress work on Android?" where both you have the same code listed and Terry Peterson made a modification to your code.  I then found on https://www.atozed.com/forums/thread-798.html how to use the procedure.

 

The result was a success using both your procedure and Terry's procedure.  I will run with this as long as Android leaves it alone.

 

You made my day.  Thank you.

Share this post


Link to post
Guest

I had to discount Terry Peterson's rendition because his SubnetMask function created an error "E2038 Illegal character in input file:: '%'" in my Sydney and Tokyo compilers.  Not sure why.  Alexandria compiled fine.  Checked my compiler settings and there was pretty much no difference between the versions.  Oh well.  Another day in paradise.

Share this post


Link to post
3 hours ago, TazKy said:

"E2038 Illegal character in input file:: '%'" in my Sydney and Tokyo compilers.

Only Delphi 11 supports binary constant in the code prefixed with %. In order to use the source in older version of Delphi you should convert the constant to hex or decimal numbers.

Share this post


Link to post
Guest

Thanks, good to know.

 

By the way, I got rid of my brain freeze and remembered "$FF" which works for all Delphi versions, right?  Terry Peterson's code is back in action.

Edited by Guest

Share this post


Link to post
On 3/9/2023 at 5:22 PM, Remy Lebeau said:

So, I'm still wondering why you actually need to query the device IP at all.

Sorry for resurrecting an old thread, but I too am looking to get the IP address of an Android device and will probably use your recommendation as a starting off point.  However, perhaps in my case I do not need to get he IP address.  In my scenario we have multiple locations throughout the state.  I have an application that is on a device connected to a given location's WiFi and the manager logs into the device to process transactions.  I can record "who" is processing the transactions, but I would also like to know "where" they are being processed.  Each of our location networks follow a standard LAN configuration in which I can read on of the octets and know which network the device was on when the transaction was processed.  I could do this based on various other device data, but these tablets are broken not infrequently, so a more reliable constant in my mind would be to know which of our networks it was on.

Share this post


Link to post
6 hours ago, GenoR said:

I can record "who" is processing the transactions, but I would also like to know "where" they are being processed.  Each of our location networks follow a standard LAN configuration in which I can read on of the octets and know which network the device was on when the transaction was processed.

And, what if the LAN configuration has to be changed in the future?

6 hours ago, GenoR said:

I could do this based on various other device data, but these tablets are broken not infrequently, so a more reliable constant in my mind would be to know which of our networks it was on.

Why not simply have a field in the app's configuration to specify the location?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×