I am building a Cordova app for android platform.
I need to get the user's country.
I know that the geolocalisation gives the GPS coordinates.
Is there a way to have the country without using any external API? if not possible what is the best solution?
There's important difference from UX and legal perspective on what country do you need:
Country of current location: use geolocation API and any mapping solution. This is the only reliable way to determine country of location, since detection by IP or SIM card may only identify the country of telecom provider. Note, that country of the current location is not the country of citizenship and it does not allow to determine user's language or locale preferences.
Country as the context for localization: use ECMAScript Internationalization API[1] and cordova-globalization-plugin[2] as a fallback. Note, that these APIs do not provide location information at all: language and locale information are not the same as user's country (e.g. user may choose french locale and en_US language, while living in Monaco and being a citizen of Russia).
Country of citizenship. In some cases, it is a critical information for your service (e.g. when personal data of the user collected by the client-server system has to be physically processed in the country of citizenship as required by laws). The only way to determine it is to ask the user and require the honest answer from him by your Terms of Service. Note, that country of citizenship does not determine localization settings or user's current location.
[1] http://www.ecma-international.org/ecma-402/1.0/
[2] https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-globalization/
I can think of a few options. The list is provided below and it is ordered by least effort needed and on the other hand how accurate will the information be.
Use user's locale string provided by Globalization plugin, it may contain the country code next to language code such as "en-US" or "en-GB".
Usage
function successCallback(obj) {
var locale = obj.value;
}
navigator.globalization.getPreferredLanguage(successCallback, errorCallback);
Only for Android: Use plugin such as Device Information plugin which allows you to access the Android's Telephony Manager's information. From this information you are able to get the
Country ISO of your phone network provider
according to the plugin author. To use the plugin your code would look something like this
deviceInfo.get(function(result) {
console.log("result = " + result);
}, function() {
console.log("error");
});
where the result will contain your netCountry called field as part of the string returned.
Figure the GPS to country conversion by yourself based on the country borders as GPS. One possible map (dataset) is available [here](World Borders Dataset). I would though recommend just using some external API to give that information for you.
If your app is only for phone or device with sim, you can use sim info plugin, https://github.com/dtmtec/cordova-plugin-carrier.
A simple solution is create a custom plugin and use Google geocoder, this code return location from latitude and longitude... This isn't for cordova, you need make some changes
try {
Geocoder gcd = new Geocoder(this, Locale.getDefault());
List<Address> addresses = gcd.getFromLocation(latitude, longitude, 1);
if (addresses.size() > 0)
String cityname = addresses.get(0).getLocality();
String country = addresses.get(0).getCountryName();
} catch (IOException e) {
e.printStackTrace();
}
Related
I have a Blog App where I write Bussiness Content for Global as well as some country-specific content. Like Special posts for India, Indonesia, etc.
That's why I need a way to find from which country the user is to provide specific content.
But, I don't want to use the GeoLocator Plugin because It will ask the
User for location. I only want the user's country, not the specific
location but the permission dialog didn't specify that which can make
the user anxious about why this app needs Location Permission. That's
why I want a way to get user's Country without an implicit permission
dialog asking for their location.
I have tried the following ways but none of them gave the exact country name.
import 'dart:io' show Platform;
String localeName = Platform.localeName;
// this returns language device is using which mostly comes us en_US so this is of no use
Locale myLocale = Localizations.localeOf(context);
// This returned the US as the country despite the App being opened and used in India.
Well, I finally found an easy and simple way to get users' country.
http://ip-api.com/json
This link returns the Users' location in a JSON format. So All one has to do now, is to make a Get request to the above link/API and decode the JSON to Map.
For that First Install HTTP Package:
Pubspec.yaml:
dependencies:
http:
Code:
import 'package:http/http.dart' as http;
import 'dart:convert';
Response data = await http.get('http://ip-api.com/json');
Map data = jsonDecode(data.body);
String country = data['country'];
EDIT:
As mentioned by good people,
Free Version Limit is 45 HTTP requests per minute from an IP address.
Locale gives you the language that the device user has set. It does not necessarily indicate their country of birth. It definitely does not tell you their country of residence. It may be that in many cases the person IS in the country of the language code but that is not guaranteed. The only way to know where they are is by location.
Update
Regarding your comment. If you mean where to get the country name based on the language code you get from the device locale, then have a look at this post. I haven't tried it myself but it seems promising. https://dev.to/thealphamerc/get-search-filter-countries-data-using-countryprovider-flutter-plugin-1epc
try this
import 'dart:io' show Platform;
String localeName = Platform.localeName
or try this
please use package devicelocale
I have tested with real device, it works fine
code snippet
String locale = await Devicelocale.currentLocale;
I am making some application that will be largely user driven and of course that means their will be trouble makers who probably will enter fake data into it using swear words or worse change valid data to bad data(ie changing to swear words)
Of course measures will be taken to try to curb this but in the end of the day I want to have the option to ban someone from my application.
My first thought is ban their account by email address. I was also thinking that maybe on top of that ban their devices.
My questions is is what unique id can I use from their phone if they use
Andriod
Iphone
Blackberry
Windows Phone 7/8
and how unique is it? Can it be easily changed?
For Windows Phone you should be able to use DeviceExtendedProperties. Specifically the DeviceUniqueId property.
Be aware though that, as they say in that article, if you use a device id to ban a user, then any future user of that same device will be banned from your app, even if they've done nothing wrong.
There are 2 identifiers that can be used together to identify a specific device and user.
The DeviceUniqueId and WindowsLiveAnonymousId
the first one is the device, and as noted, anyone who uses the device after the banned user will also be banned.
The WindowsLiveAnonymousId is unique to the user. I have seen this same identifier across 3 separate devices and it is always the same for the users LiveId.
I use the following 2 methods to get these ids for identifying game players for leader-boards:
//Note: to get a result requires ID_CAP_IDENTITY_DEVICE
// to be added to the capabilities of the WMAppManifest
// this will then warn users in marketplace
public static byte[] GetDeviceUniqueId()
{
byte[] result = null;
object uniqueId;
if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId))
result = (byte[])uniqueId;
return result;
}
// NOTE: to get a result requires ID_CAP_IDENTITY_USER
// to be added to the capabilities of the WMAppManifest
// this will then warn users in marketplace
public static string GetWindowsLiveAnonymousId()
{
string result = String.Empty;
object anid;
if (UserExtendedProperties.TryGetValue("ANID", out anid))
{
if (anid != null && anid.ToString().Length >= (AnidLength + AnidOffset))
{
result = anid.ToString().Substring(AnidOffset, AnidLength);
}
}
return result;
}
They are used as such:
string deviceUniqueId = String.Empty;
for (int i = 0; i < GetDeviceUniqueId().GetLength(0); i++)
{
deviceUniqueId += GetDeviceUniqueId().GetValue(i);
}
DeviceUniqueIDTextBlock.Text = deviceUniqueId;
WindowsLiveAnonymousIDTextBlock.Text = GetWindowsLiveAnonymousId().ToString(CultureInfo.InvariantCulture);
I did a post last May about getting system info on WP7. This code is found here: http://www.adambenoit.com/applications/system-info-windows-phone/
Hope this helps.
All these devices have network interfaces with unique MAC addresses which by definition are constant - the MAC address is burned into the hardware and cannot be [easily] spoofed, especially on a mobile device. I would hash the MAC address and use that as the key. Pretty common practice on iOS once apple banned the use of UDIDs.
I would use the guid method. Though this can be circumvented by uninstalling and re-installing the app. Nothings perfect though
How to create a GUID/UUID using the iPhone SDK
How to get GUID in android?
How to create a GUID on Windows Phone
http://msdn.microsoft.com/en-us/library/system.guid.newguid(v=vs.95).aspx
How to create a GUID on Blackberry http://supportforums.blackberry.com/t5/Java-Development/how-to-generate-GUID/td-p/289947
I've created an autocomplete address search text box. My problem is that I just can't make it work fine:
Addresses are out of the bounding box usually, whatever I do - this didn't help.
Finds addresses that doesn't contain the typed text.
Finds less addresses, than max but it doesn't contain the good result.
The result list is totally irrelevant sometimes.
I need to type almost the whole address to get the correct result.
Source:
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses = null;
try {
if (Geocoder.isPresent()) {
// Bounding box: Hungary
addresses = geocoder.getFromLocationName(text, 5, 46.13, 21.96, 48.89, 16.69);
}
} catch (IOException e) {
Log.v(tag, "Geocoding error: " + e.getMessage());
e.printStackTrace();
}
My aim is to make an address search text box which gets the same result as in Android Maps seach text box - except the previously typed/favourite addresses and etc., which is an other story.
The Google Places Autocomplete API may be of help. As far as I know you must license it for use in commercial apps. If your app is for free then you should be fine.
EDIT about inaccurate Geocoder results:
I haven't yet played around much with Geocoder. But what I can tell you so far is the following:
You need to take into consideration that on some devices all methods return null (check Geocoder.isPresent() to be sure) because Geocoder relies on some underlying implementation that can be missing on some devices.
And it is also possible that these results come from an other Geocoder engine / service than Google Places.
On top of that the query results are never perfect. You rarely get the exact address of the current location either because the location is off or because the Geocoder data is not accurate enough (or simply outdated).
If you really need an accurate address you should give the user both a list of best candidate options and some means for manually editing the address.
If you need more accurate results based on the location name you could take a look at available online services that perform better for your needs. One example is geonames.org. If their database is good enough for you, then you need to get or implement some Java API for interfacing with the service of your choice and use that instead Geocoder.
I have the following code in my Android program
List<Address> addressList = geoCoder.getFromLocation(37.790551,-122.433931, 1);
if (!addressList.isEmpty()) {
address = addressList.get(0);
String number = address.getSubThoroughfare();
String streetName = address.getThoroughfare();
.....
}
This is a request to essentially get a street name (hence the 1) from a latitude and longitude in San Francisco.
When I execute this program on a phone in Europe (specifically Ireland) number is returned as 2250-2290 and streetname is returned as Fillmore St.
When I get a friend to run the same code on his phone in California number is null and streetname is still Fillmore st.
I've seen other SO questions allude to region settings but is this possible that the geographical location can affect the query in the Android API?
The Javascript Geocoding API mentions region bias. I wonder is it possible to do something similar in the Android API. I did try creating the Geocoder as
Geocoder geoCoder = new Geocoder(getApplicationContext(), Locale.US);
but this does not re-recreate the California based result.
From getting people to run identical code on different continents it seems that location is indeed a factor.
The Javascript geocoding allows you to specify a region though
Are the phones running different versions of android? Also, another thing to keep in mind is that "The Geocoder class requires a backend service that is not included in the core android framework." So, if the two phones are calling upon different backend services to query for the Geocoder, that may explain the output you are seeing.
I think with Android 1.5, they included a Google API backend service implementation for Geocoder. I don't know if newer versions of Android and the Google API made changes to the Geocoder implementation that may be giving you different results or it's coming from some other backend service.
I want to search for GPS locations for with Google Maps. I have already registered with Google Maps API, and got the key. I can successfully pinpoint my current location on a map. The next part is to search for items around the current GPS location.
Approach 1: I tried using Android's geocoder.getFromLocationName("UPS",5) but I am not getting anything.
Approach 2: hit Google https://maps.googleapis.cm/maps/apo/place/search but it needs a client id. To get a client id I have to create a premier account. Do I have to do all this?
Any suggestion how to use maps to search location for Android?
"GPS" is the place you're looking up? Not a city or street name? I think that's the problem here.
Maybe look at:
How can I find the latitude and longitude from address?
You will want to use a better "address" other than UPS to find locations using Geocoder. Do you realize how many UPS locations will be found. getFromLocationName() is best used with detailed location info and a locale directive so it limits its searching to the Locale you specify. Also, you will frequently get IOExceptions in the emulator. Lastly using SDK 2.3 and above will not work with Geocoder.
Try something like this:
Geocoder geocoder = new Geocoder(this, Locale.US);
String staddress = "Georgia Tech, Atlanta, GA";
try{
List<Address> loc = geocoder.getFromLocationName(staddress, 5);
}
catch(IOException e) {
Log.e("IOException", e.getMessage());
Toast.makeText(this, "IOException: " + e.getMessage(),20).show();
Notice how the locale is set to US when I new up my Geocoder. Also notice the try catch around the call to geocoder. That will catch any IO Exceptions and allow you ot handle them as I did using a Toast message and some other flow control statements that are out of sight