构建最可靠的用户国家机制

时间:2014-04-02 14:36:01

标签: java android location country

在我目前正在处理的应用程序中,非常需要尽可能快地确定用户所在国家/地区并尽可能可靠。我决定依靠三种方式来寻找用户国家;每个人都有其优点和缺点:

  1. 获取SIM国家/地区的Android内部方法。
  2. 天气预报。
  3. IP to Location API。
  4. 以下是三段代码:

    1。获取SIM国家/地区的Android内部方法:

    public static String getUserCountry(Context context) {
        try {
            final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            final String simCountry = tm.getSimCountryIso();
            if (simCountry != null && simCountry.length() == 2) { // SIM country code is available
                 CupsLog.d(TAG, "getUserCountry, simCountry: " + simCountry.toLowerCase(Locale.US));
                return simCountry.toLowerCase(Locale.US);
            }
            else if (tm.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { // device is not 3G (would be unreliable)
                String networkCountry = tm.getNetworkCountryIso();
                if (networkCountry != null && networkCountry.length() == 2) { // network country code is available
                     CupsLog.d(TAG, "getUserCountry, networkCountry: " + networkCountry.toLowerCase(Locale.US));
                    return networkCountry.toLowerCase(Locale.US);
    
                }
            }
        }
        catch (Exception e) { }
        return null;
    }
    

    2。地理编码

      public static void getCountryCode(final Location location, final Context context) {
       CupsLog.d(TAG, "getCountryCode");
    
       AsyncTask<Void, Void, String> countryCodeTask = new AsyncTask<Void, Void, String>() {
    
           final float latitude = (float) location.getLatitude();
           final float longitude = (float) location.getLongitude();
           List<Address> addresses = null;
           Geocoder gcd = new Geocoder(context);
           String code = null;
    
           @Override
           protected String doInBackground(Void... params) {
               CupsLog.d(TAG, "doInBackground");
               try {
                   addresses = gcd.getFromLocation(latitude, longitude, 10);
                   for (int i=0; i < addresses.size(); i++)
                   {
                       if (addresses.get(i) != null && addresses.get(i).getCountryCode() != null)
                       {
                           code = addresses.get(i).getCountryCode();
                       }
                   } 
               } catch (IOException e) {
                   CupsLog.d(TAG, "IOException" + e);
               }
               return code;
           }
    
           @Override
           protected void onPostExecute(String code) 
           {
               if (code != null)
               {
                   CupsLog.d(TAG, "getCountryCode :" + code.toLowerCase());
                   UserLocation.instance.setCountryCode(code.toLowerCase());
                   CookieUtil.formatLangueageAndLocationCookie();
                   CookieUtil.instance.instantateCookieUtil(context);
               }
           }
       };
    
       if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
           CupsLog.d(TAG, "countryCodeTask.execute();");
           countryCodeTask.execute();
       } else {
           CupsLog.d(TAG, "countryCodeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);");
           countryCodeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
       }
    }
    

    第3。 IP到位置API:

     private void getUserCountryByIp() {
    
            AsyncHttpClient client = new AsyncHttpClient();
            client.setCookieStore(CookieUtil.instance.getPersistentCookieStore());
    
            String userCountryApi = "http://ip-api.com/json";
            CupsLog.i(TAG, "country uri: " + userCountryApi);
    
    
            client.get(userCountryApi, new JsonHttpResponseHandler() {
                @Override
                public void onSuccess(JSONObject orderResponseJSON) {
                    CupsLog.i(TAG, "onSuccess(JSONObject res)");
                    try 
                    {
                        CupsLog.i(TAG, "JsonResponse: "+ orderResponseJSON.toString(3));
                        String tempString = orderResponseJSON.getString("countryCode");
                        if (tempString != null)
                        {
                            //countryCodeFromIpApi = tempString.toLowerCase();
                            UserLocation.instance.setCountryCode(tempString.toLowerCase());
                            CookieUtil.formatLangueageAndLocationCookie();
                            CookieUtil.instance.instantateCookieUtil(LoginActivity.this);
                            isGotCountryFromIp = true;
                        }
                    } catch (JSONException e) {
                        CupsLog.i(TAG, "JSONException: " + e);
                    }
                }
    
                @Override
                public void onFailure(Throwable arg0, JSONObject orderResponseJSON) {
                    CupsLog.i(TAG, "onFailure");
                    try {
                        CupsLog.i(TAG, "JsonResponse: "+ orderResponseJSON.toString(3));
                    } catch (JSONException e) {
                        CupsLog.i(TAG, "JSONException: " + e);
                    }
                }
    
                @Override
                public void onFinish() {
                    CupsLog.i(TAG, "onFinish");
                    super.onFinish();
                }
            });
        }
    

    现在我有3种方法工作得很好,我的问题更多的是Java问题。第一种方法立即给我结果,而另外两种(2,3)是潜在的长期运行任务。更多的是第一个选项是最不可靠的选项,因为用户可以使用SIM卡前往不同的国家/地区。第二个更可靠,但有时仍然不返回一个国家(取决于用户的位置)。第三个是我发现最可靠的一个,但也是最长的。

    问题:了解这些信息,我将如何构建一个方法,以正确的顺序使用这3种方法获得可靠性观点并考虑长期运行的任务因素?

1 个答案:

答案 0 :(得分:1)

不幸的是,没有真正可靠的方法来确定用户的物理位置(例如他/她的手机),因为:

  • SIM卡可能在其他国家/地区购买和/或制造;
  • 地理编码(基于GPS / GLONASS坐标的AFAIU)如果用户禁用或者没有可见的卫星(例如地下),可能会给出错误的(~10m)结果或根本没有结果;
  • 通过IP解析国家/地区也可能会给您错误的结果,例如因为使用了VPN;

所以我的建议是询问用户,他目前在哪个国家,并愿意“告诉”你。