Last active
December 31, 2018 18:39
-
-
Save HugoGresse/4ae1574993e698c43b5e to your computer and use it in GitHub Desktop.
Location Google Api Client play services using reflection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void getLocation(Context context) { | |
Log.d(LOG_TAG, "getLocation"); | |
if (context.getPackageManager().checkPermission( | |
Manifest.permission.ACCESS_FINE_LOCATION, context.getPackageName()) == PackageManager.PERMISSION_GRANTED || | |
context.getPackageManager().checkPermission( | |
Manifest.permission.ACCESS_COARSE_LOCATION, context.getPackageName()) == PackageManager.PERMISSION_GRANTED) { | |
try { | |
Class<?> apiClientBuilderClass = Class.forName("com.google.android.gms.common.api.GoogleApiClient$Builder"); | |
Class<?> connectionCallbackClass = Class.forName("com.google.android.gms.common.api.GoogleApiClient$ConnectionCallbacks"); | |
Class<?> connectionFailedCallbackClass = Class.forName("com.google.android.gms.common.api.GoogleApiClient$OnConnectionFailedListener"); | |
Class<?> locationServicesClass = Class.forName("com.google.android.gms.location.LocationServices"); | |
Constructor<?> constructorApiBuilder = apiClientBuilderClass.getConstructor(Context.class); | |
Object objectApiBuilder = constructorApiBuilder.newInstance(mContext); | |
// Create intance of listener ConnectionCallbacks | |
Class<?>[] connectionClassArray = new Class<?>[1]; | |
connectionClassArray[0] = connectionCallbackClass; | |
sGoogleApiClientListener = Proxy.newProxyInstance( | |
connectionCallbackClass.getClassLoader(), connectionClassArray, new GoogleApiClientListener()); | |
Method connectionMethodObject = apiClientBuilderClass.getMethod("addConnectionCallbacks", connectionCallbackClass); | |
connectionMethodObject.invoke(objectApiBuilder, sGoogleApiClientListener); | |
// Create instance of OnConnectionFailedListener listener | |
Class<?>[] connectionFailedClassArray = new Class<?>[1]; | |
connectionFailedClassArray[0] = connectionFailedCallbackClass; | |
sGoogleApiClientFailedListener = Proxy.newProxyInstance( | |
connectionFailedCallbackClass.getClassLoader(), connectionFailedClassArray, new GoogleApiClientFailedListener()); | |
Method connectionFailedMethodObject = apiClientBuilderClass.getMethod("addOnConnectionFailedListener", connectionFailedCallbackClass); | |
connectionFailedMethodObject.invoke(objectApiBuilder, sGoogleApiClientFailedListener); | |
// Add Api | |
Method addApiMethod = apiClientBuilderClass.getMethod("addApi", Class.forName("com.google.android.gms.common.api.Api")); | |
addApiMethod.invoke(objectApiBuilder, locationServicesClass.getField("API").get(null)); | |
// Build | |
Method buildMethod = apiClientBuilderClass.getMethod("build"); | |
sGoogleApiClient = buildMethod.invoke(objectApiBuilder); | |
// Connect | |
for (Method method : sGoogleApiClient.getClass().getMethods()) { | |
if (!"connect".equals(method.getName())) { | |
continue; | |
} | |
method.invoke(sGoogleApiClient); | |
break; | |
} | |
} catch (Exception e) { | |
// Location is not essential, so it's not an error | |
Log.v(LOG_TAG, "Exception on getLocation " + Log.getStackTraceString(e)); | |
} | |
} else { | |
sLocation = ""; | |
} | |
} | |
// GoogleApiClient for Locationsucceded | |
public void onConnected() { | |
Location lastLocation = null; | |
try { | |
// FusedLocationApi is a field of LocationServices, getting it. | |
Class<?> locationServicesClass = Class.forName("com.google.android.gms.location.LocationServices"); | |
Class<?> locationProviderClass = Class.forName("com.google.android.gms.location.FusedLocationProviderApi"); | |
for (Method method : locationProviderClass.getMethods()) { | |
if (!"getLastLocation".equals(method.getName())) { | |
continue; | |
} | |
Object object = locationServicesClass.getField("FusedLocationApi").get(null); | |
lastLocation = (Location) method.invoke(object, sGoogleApiClient); | |
break; | |
} | |
} catch (Exception e) { | |
// Location is not essential, so it's not an error | |
Log.v(LOG_TAG, "Exception on invoke onConnected for getLastLocation" + Log.getStackTraceString(e)); | |
} | |
// Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(sGoogleApiClient); | |
if (lastLocation != null) { | |
sLocation = lastLocation.getLatitude() + "," + lastLocation.getLongitude(); | |
Log.d(LOG_TAG, "Location received : " + sLocation); | |
} else { | |
sLocation = ""; | |
} | |
newResourcesAvailable(); | |
unregisterConnectionCallbacks(); | |
} | |
// GoogleApiClient for Location failed somewhere | |
public void onConnectionSuspended() { | |
sLocation = ""; | |
newResourcesAvailable(); | |
unregisterConnectionCallbacks(); | |
} | |
// GoogleApiClient for Location failed somewhere | |
public void onConnectionFailed() { | |
sLocation = ""; | |
newResourcesAvailable(); | |
unregisterConnectionCallbacks(); | |
} | |
private void unregisterConnectionCallbacks(){ | |
for (Method method : sGoogleApiClient.getClass().getMethods()) { | |
if (!"unregisterConnectionCallbacks".equals(method.getName())) { | |
continue; | |
} | |
try { | |
method.invoke(sGoogleApiClient, sGoogleApiClientListener); | |
} catch (Exception ignored) { | |
// Exception always occur here but cannot make it work | |
} | |
break; | |
} | |
for (Method method : sGoogleApiClient.getClass().getMethods()) { | |
if (!"unregisterConnectionFailedListener".equals(method.getName())) { | |
continue; | |
} | |
try { | |
method.invoke(sGoogleApiClient, sGoogleApiClientFailedListener); | |
} catch (Exception ignored) { | |
// Exception always occur here but cannot make it work | |
} | |
break; | |
} | |
} | |
protected class RetrieveAdvertisingId extends AsyncTask<Void, Void, String> { | |
@Override | |
protected String doInBackground(Void... params) { | |
String id = ""; | |
try { | |
Object AdvertisingInfoObject = getAdvertisingInfoObject(mContext); | |
id = (String) invokeInstanceMethod(AdvertisingInfoObject, "getId", null); | |
} catch (Exception e) { | |
// Catch reflection exception and GooglePlayServicesNotAvailableException | | |
// GooglePlayServicesRepairableException | |
Log.e(LOG_TAG, "Exception while getting AdvertisingId", e); | |
} | |
return id; | |
} | |
@Override | |
protected void onPostExecute(String advertisingId) { | |
super.onPostExecute(advertisingId); | |
if (advertisingId != null && !advertisingId.isEmpty()) { | |
Log.i(LOG_TAG, "Advertising ID retrieved: " + advertisingId); | |
sAdvertisingId = advertisingId; | |
} else { | |
Log.e(LOG_TAG, "AdversitingId is not available"); | |
sAdvertisingId = ""; | |
} | |
AsynchronousParameterManager.this.newResourcesAvailable(); | |
} | |
} | |
/** | |
* Returns the AdvertisingIdInfo object | |
* | |
* @param context the android context | |
* @return the advertising id information object | |
* @throws Exception | |
*/ | |
private Object getAdvertisingInfoObject(Context context) throws Exception { | |
return invokeStaticMethod( | |
"com.google.android.gms.ads.identifier.AdvertisingIdClient", | |
"getAdvertisingIdInfo", | |
new Class[]{Context.class}, | |
context | |
); | |
} | |
/** | |
* Invokes a static method within a class | |
* if it can be found on the classpath. | |
* | |
* @param className The full defined classname | |
* @param methodName The name of the method to invoke | |
* @param cArgs The args that the method can take | |
* @param args The args to pass to the method on invocation | |
* @return the result of the method invoke | |
* @throws Exception | |
*/ | |
private Object invokeStaticMethod(String className, String methodName, | |
Class[] cArgs, Object... args) throws Exception { | |
Class classObject = Class.forName(className); | |
return invokeMethod(classObject, methodName, null, cArgs, args); | |
} | |
/** | |
* Invokes a method on a static instance | |
* within a class by reflection. | |
* | |
* @param instance The instance to invoke a method on | |
* @param methodName The name of the method to invoke | |
* @param cArgs The args that the method can take | |
* @param args The args to pass to the method on invocation | |
* @return the result of the method invoke | |
* @throws Exception | |
*/ | |
private Object invokeInstanceMethod(Object instance, String methodName, | |
Class[] cArgs, Object... args) throws Exception { | |
Class classObject = instance.getClass(); | |
return invokeMethod(classObject, methodName, instance, cArgs, args); | |
} | |
/** | |
* Invokes methods of a class via reflection | |
* | |
* @param classObject The class to attempt invocation on | |
* @param methodName The name of the method to invoke | |
* @param instance The object instance to invoke on | |
* @param cArgs The args that the method can take | |
* @param args The args to pass to the method on invocation | |
* @return the result of the method invoke | |
* @throws Exception | |
*/ | |
private Object invokeMethod(Class classObject, String methodName, Object instance, | |
Class[] cArgs, Object... args) throws Exception { | |
Method methodObject = classObject.getMethod(methodName, cArgs); | |
return methodObject.invoke(instance, args); | |
} | |
private class GoogleApiClientListener implements InvocationHandler { | |
@Override | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
try { | |
if (args != null) { | |
if (method.getName().equals("onConnected")) { | |
AsynchronousParameterManager.this.onConnected(); | |
} else if (method.getName().equals("onConnectionSuspended") ) { | |
AsynchronousParameterManager.this.onConnectionSuspended(); | |
} | |
} else { | |
return 0; | |
} | |
} catch (Exception e) { | |
throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); | |
} | |
return null; | |
} | |
} | |
private class GoogleApiClientFailedListener implements InvocationHandler { | |
@Override | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
Object result = null; | |
try { | |
if (method.getName().equals("onConnectionFailed")) { | |
AsynchronousParameterManager.this.onConnectionFailed(); | |
} | |
return 0; | |
} catch (Exception e) { | |
throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment