Guest Posted March 8, 2023 (edited) 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 March 8, 2023 by Guest Share this post Link to post
Remy Lebeau 1396 Posted March 8, 2023 (edited) 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 March 8, 2023 by Remy Lebeau Share this post Link to post
Guest Posted March 9, 2023 (edited) 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 March 9, 2023 by Guest Share this post Link to post
programmerdelphi2k 237 Posted March 9, 2023 Quote uses System.Generics.Collections; var MyList : TList<TJInetAddress>; Share this post Link to post
Guest Posted March 9, 2023 Sorry, it did not help. Just shifted the errors to other areas. Where do I use MyList? Share this post Link to post
programmerdelphi2k 237 Posted March 9, 2023 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
programmerdelphi2k 237 Posted March 9, 2023 3 hours ago, TazKy said: function getIpAddresses: TList<JInetAddress>; you need "uses System.Generics.Collection;" Share this post Link to post
Guest Posted March 9, 2023 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
Remy Lebeau 1396 Posted March 9, 2023 (edited) 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 March 9, 2023 by Remy Lebeau Share this post Link to post
Remy Lebeau 1396 Posted March 9, 2023 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 Posted March 9, 2023 (edited) 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 March 9, 2023 by Guest Share this post Link to post
programmerdelphi2k 237 Posted March 9, 2023 did try use "AppTethering?"... = UDP and TCP = Indy behind scenes!!! easy setup just create a group/password and it's ready same network or not. Network/Bluetooth http://www.malcolmgroves.com/blog/?p=1842 Share this post Link to post
Remy Lebeau 1396 Posted March 9, 2023 (edited) 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 March 9, 2023 by Remy Lebeau Share this post Link to post
Dave Nottage 557 Posted March 9, 2023 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 Posted March 10, 2023 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
Jirka52 2 Posted March 10, 2023 Hi. I just wrote the same application for Android - bar code scanner for our store manager. I used communication via REST server and it works perfect. See: https://docwiki.embarcadero.com/RADStudio/Sydney/en/Tutorial:_Using_a_REST_DataSnap_Server_with_an_Application_and_FireDAC Share this post Link to post
Guest Posted March 10, 2023 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
Lajos Juhász 293 Posted March 10, 2023 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 Posted March 11, 2023 (edited) 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 March 11, 2023 by Guest Share this post Link to post
GenoR 0 Posted October 6, 2023 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
Remy Lebeau 1396 Posted October 6, 2023 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