Related
I am currently considering porting a app that I start developping with react-native to codenameone. For this, I am still checking the feasability and the amount of work it would requiere (as I would have to port or developp some native library binding from react-native to codenameone because codenameone miss some of my needs, like socket.io support for example). The free codenameone build cloud service beeing limited to app of 1Mb, I have to make my test builds locally (with only a few test classes and the use of the google maps cn1lib, my test app is already above the 1Mb limit)
Sadly, there is no free documentation on codenameone on how to perform local builds and actually I couldn't find any instructions on internet on how to do it (I only found, on a blog post, some basic and deprecated instructions on how to perform a local iOS build but nothing for Android). So I had to figure it out myself...
After some time spent digging into gradle configuration parametters, I finally succeed into building a basic codenameone app localy that works on my android test device. But the problem is that, when I add an external cn1lib (the google maps native cn1lib https://github.com/codenameone/codenameone-google-maps ), my app bug when oppening a screen that depends from this lib.
In the android error log, I could find this message:
D/MyApplication( 551): [EDT] 0:0:0,99 - Exception: java.lang.ClassCastException - com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface
W/System.err( 551): java.lang.ClassCastException: com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface
W/System.err( 551): at com.codename1.system.NativeLookup.create(Unknown Source)
W/System.err( 551): at com.codename1.googlemaps.MapContainer.<init>(MapContainer.java:171)
W/System.err( 551): at com.codename1.googlemaps.MapContainer.<init>(MapContainer.java:151)
W/System.err( 551): at com.tbdlab.testapp.MyApplication.start(MyApplication.java:207)
W/System.err( 551): at com.tbdlab.testapp.MyApplicationStub.run(MyApplicationStub.java:183)
W/System.err( 551): at com.codename1.ui.Display.processSerialCalls(Unknown Source)
W/System.err( 551): at com.codename1.ui.Display.mainEDTLoop(Unknown Source)
W/System.err( 551): at com.codename1.ui.RunnableWrapper.run(Unknown Source)
W/System.err( 551): at com.codename1.impl.CodenameOneThread$1.run(Unknown Source)
W/System.err( 551): at java.lang.Thread.run(Thread.java:818)
I don't really understand why InternalNativeMapsImpl could not be cast into NativeInterface as I looked into the dex file of my compiled apk and all the necessary classes (for android) from the google maps cn1lib are correctly included (So I have com.codenameone.googlemaps.InternalNativeMaps, com.codenameone.googlemaps.InternalNativeMapsImpl and com.codenameone.googlemaps.MapContainer) and so are the codenameone native interface classes they depend on (com.codename1.system.NativeInterface, com.codename1.impl.android.LifecycleListener...). And I decompilled them and the code is correct (I do not use any obfuscation method anyway so there is no real reason why the compiled code would have differ from the source code). There is probably something that I am missing here to make a local codenameone build with the usage of a cn1lib.
So has anyone already succeed into making a local build with the usage of a cn1lib that perform native bindings? If yes, what is the exact procedure?
I really hope someone would be able to help, because, at this point, I am seriously considering to stick with react-native (which I am quite pleased with, exept the fact that it is not completely native) or to jump into flutter (or kotlin native) even if I still think codenameone offers many advantages over these other solutions (but not beeing able to perform local builds during the development phase is just a complete no-go for me)
As said, in some of my tests (where I use the full set of cn1libs I would need + some custom libs), I am already above the 1Mb limitation (the server rejected my test builds for this reason). So using the free build cloud server during the development phase is not an option for me (Anyway I won't use a solution if I am not sure I can be completely independent if necessary. To make my release builds I would certainly take a subscription and use the cloud buid server as it is far more convenient than tweeking a local server, furthermore that I don't own a Mac computer (I only have a test iphone) and need to borrow one when I want to make some iOS build ;) . But I want to be sure that if, for any reason, your service dissapear, I will still be able to make my builds. Furthermore, I don't see the point of paying a subscription during the developpment phase of my app (that could take me months) especially as I am not certain I would use codenameone as a final solution (I still have to check the amount of work it would requiere to adapt some of the libs I already have for react-native to codenameone)). That is the reason why I try to make a local build.
Concerning the socket.io library, I already started to create a cn1lib that will use native solutions (https://github.com/socketio/socket.io-client-java for android, https://github.com/socketio/socket.io-client-swift for iOS, and the original socket.io lib for javascript). This is not really an issue and it was just to give an example of libraries I would have to create in codenameone if I want to switch from react-native.
In what concerns how cn1lib works, I already figured that out, I included into my android project all the necessary class of the cn1 google-maps lib (so I included the content from main.zip, nativeand.zip and stubs.zip in my project) and checked in the .dex files of my generated apk that they are actually correctly packaged in them, as already said. So my problem doesn't seems to be that I forgot to include some class of the cn1lib in my project but something else. The error message is: Exception: java.lang.ClassCastException - com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface so it doesn't refer to a Class not found but to a cast exception... I don't really know what can cause this issue. I took the codenameone core classes from here https://github.com/codenameone/CodenameOne/tree/master/CodenameOne/src/
https://github.com/codenameone/CodenameOne/tree/master/Ports/Android http://github.com/codenameone/codenameone-skins
to include them in my project, so I think I didn't miss one. And when building a project that doesn't use a cn1lib (like a simple "hello word" app), it compiles and run just fine on my android test device.
The problem, is really just when my app try to create a googlemap view, where it returns the cast exception (and then default to try to create an html browser mapview and fails here as it is missing some html file).
So it is probably a configuration problem ( may it be a problem with the java version used by the compiler as native class files where already compiled in the cn1lib main.zip file?)
Here is the gradle build file I use:
buildscript {
repositories {
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'me.tatarka:gradle-retrolambda:3.2.0'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
dexOptions {
// Prevent OutOfMemory with MultiDex during the build phase
javaMaxHeapSize "4g"
}
lintOptions {
checkReleaseBuilds false
}
defaultConfig {
applicationId "com.tbdlab.testapp"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //my proguard files are actually empty so no obfuscation is performed. I checked it in the generated apk
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7//.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_7//.VERSION_1_8
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.google.android.gms:play-services:9.4.0' //compile 'com.google.android.gms:play-services-maps:11.8.0'
compile 'com.android.support:multidex:1.0.1'
}
and here is my AndroidManifest.xml file where I included all the permissions defined in the cn1lib:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--- Permissions requiered by the google maps cn1lib -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<application android:allowBackup="true" android:icon="#drawable/icon" android:label="MyApplication" android:name="android.support.multidex.MultiDexApplication">
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version"/>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="...masked_it_but_put_my_correct_key_here..."/>
<activity android:label="MyApplication" android:launchMode="singleTop" android:name="com.tbdlab.testapp.MyApplicationStub" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name="com.codename1.impl.android.LocalNotificationPublisher"/>
<service android:exported="false" android:name="com.codename1.impl.android.BackgroundFetchHandler"/>
<activity android:name="com.codename1.impl.android.CodenameOneBackgroundFetchActivity" android:theme="#android:style/Theme.NoDisplay"/>
<activity android:name="com.codename1.location.CodenameOneBackgroundLocationActivity" android:theme="#android:style/Theme.NoDisplay"/>
<service android:exported="false" android:name="com.codename1.location.BackgroundLocationHandler"/>
<service android:exported="false" android:name="com.codename1.location.GeofenceHandler"/>
<service android:exported="false" android:name="com.codename1.media.AudioService"/>
<activity android:excludeFromRecents="true" android:exported="false" android:name="com.google.android.gms.auth.api.signin.internal.SignInHubActivity" android:theme="#android:style/Theme.Translucent.NoTitleBar"/>
<provider android:authorities="com.tbdlab.testapp.google_measurement_service" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementContentProvider"/>
<receiver android:enabled="true" android:name="com.google.android.gms.measurement.AppMeasurementReceiver">
<intent-filter>
<action android:name="com.google.android.gms.measurement.UPLOAD"/>
</intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementService"/>
<activity android:name="com.google.android.gms.ads.AdActivity" android:theme="#android:style/Theme.Translucent"/>
I really don't see what can cause the cast exception, but in the lack of a basic tutorial on how to create local builds, I may have miss something without even knowing it...
For this test I made a really simple app than only display a native google map and it runs correctly in the simulator and compiles on the build cloud server and runs fine in my android test device. So the issue is either in my gradle build configuration (or maybe AndroidManifest.xml file even if I don't think it has any effect on the JVM) or in the codenameone core and cn1lib I included in my android project for the local build.
1mb is huge as it can fit the full google maps app and a lot more. It maps to the compiled size of the jar which starts off at 6kb. The whole cn1lib (only a portion of it is packaged) is 40kb. So I would suggest using the build servers for your tests.
Steve built some support for working with native interfaces a few years back here. He stopped maintaining it a bit after we hired him mostly due to lack of time and demand (not because we told him or anything like that). I'm not sure about the status of this but you can use it as a reference to how native interfaces work.
There is also this plugin (direct link here) which I personally didn't try.
Generally a native interface generates an intermediate class that invokes the native implementation directly. The native implementation for all platforms other than Java SE doesn't implement the native interface and shouldn't. I think I explained it somewhere in the docs but explaining it again in the case of Google Maps is super easy.
This is a method from the native interface:
public PeerComponent createNativeMap(int mapId);
This is the same method from the Android implementation class:
public android.view.View createNativeMap(int mapId);
As you can see the return value differs and we need to wrap it in a peer component to abstract that behavior. By avoiding inheritance and casting we get the flexibility of making a more sensible native API.
Here is the class our build server generates for maps, as you can see it's just "glue code":
package com.codename1.googlemaps;
import com.codename1.ui.PeerComponent;
public class InternalNativeMapsStub implements InternalNativeMaps{
private InternalNativeMapsImpl impl = new InternalNativeMapsImpl();
public void setShowMyLocation(boolean param0) {
impl.setShowMyLocation(param0);
}
public void setRotateGestureEnabled(boolean param0) {
impl.setRotateGestureEnabled(param0);
}
public void setMapType(int param0) {
impl.setMapType(param0);
}
public int getMapType() {
return impl.getMapType();
}
public int getMaxZoom() {
return impl.getMaxZoom();
}
public int getMinZoom() {
return impl.getMinZoom();
}
public long addMarker(byte[] param0, double param1, double param2, String param3, String param4, boolean param5) {
return impl.addMarker(param0, param1, param2, param3, param4, param5);
}
public void addToPath(long param0, double param1, double param2) {
impl.addToPath(param0, param1, param2);
}
public long finishPath(long param0) {
return impl.finishPath(param0);
}
public void removeMapElement(long param0) {
impl.removeMapElement(param0);
}
public void removeAllMarkers() {
impl.removeAllMarkers();
}
public PeerComponent createNativeMap(int param0) {
return PeerComponent.create(impl.createNativeMap(param0));
}
public void setPosition(double param0, double param1) {
impl.setPosition(param0, param1);
}
public void calcScreenPosition(double param0, double param1) {
impl.calcScreenPosition(param0, param1);
}
public int getScreenX() {
return impl.getScreenX();
}
public int getScreenY() {
return impl.getScreenY();
}
public void calcLatLongPosition(int param0, int param1) {
impl.calcLatLongPosition(param0, param1);
}
public double getScreenLat() {
return impl.getScreenLat();
}
public double getScreenLon() {
return impl.getScreenLon();
}
public void deinitialize() {
impl.deinitialize();
}
public float getZoom() {
return impl.getZoom();
}
public void setZoom(double param0, double param1, float param2) {
impl.setZoom(param0, param1, param2);
}
public double getLatitude() {
return impl.getLatitude();
}
public double getLongitude() {
return impl.getLongitude();
}
public long beginPath() {
return impl.beginPath();
}
public void initialize() {
impl.initialize();
}
public boolean isSupported() {
return impl.isSupported();
}
}
About socket.io you can probably just wrap the JavaScript version with a call to the BrowserComponent to get the native JS code working as a start. A full on native port can come later.
It seems you have cn1libs figured out otherwise but just for completeness this is how they are supposed to work:
The cn1lib is just a zip file containing other zip files for each platform. Refresh libs unzips the this and arranges the files in the appropriate directories under lib/impl. So you need to package the lib/impl directory matching the platform you are trying to compile with your distribution.
cn1libs also include two additional property files codenameone_library_appended.properties & codenameone_library_required.properties. Refresh libs will handle that automatically for you by setting these values into the build hints. The former values are appended to the existing build hint and the latter override an existing build hint.
Build hints effectively tell the build servers how to compile some things e.g. if we want to inject stuff into the plist, manifest etc. How this maps to a local build will vary a lot. In some cases like plistInject it would be trivial to understand but other cases might be odd. If you have a question about how a specific build hint maps to local build then you can ask that.
I am developing an android application as part of a project, and am using Google places API to display places of interest based on location. I am using the PlacePicker Inentbuilder to accomplish this.
However, when the app is run, the place picker launches and then closes immediately (about 1-2 seconds).
I have already implemented the below suggestions (that I got from other answers):
I have generated the public API key for android applications, and am including this in the meta-data tag in the app manifest.
I have enabled the "Google Places API for android" API on the developers console.
I have included the latest play services version in dependencies in build.gradle.
I have included my code and the logcat below. Do let me know if I need to include anything else.
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sampath.project.project_v2" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.api_key"
android:value="#string/google_api_key" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="#string/google_api_key" />"
<activity
android:name=".LoginActivity"
android:label="#string/title_activity_login" >
</activity>
<activity
android:name=".PlacesSample"
android:label="#string/title_activity_places_sample" >
<meta-data
android:name="com.google.android.geo.api_key"
android:value="#string/google_api_key" />
</activity>
</application>
</manifest>
Build.gradle (app module - This is the only module)
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.sampath.project.project_v2"
minSdkVersion 16
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
//compile fileTree(include: ['*.jar'], dir: 'libs')
//compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.android.support:cardview-v7:22.1.1'
compile 'com.android.support:recyclerview-v7:22.1.1'
compile 'com.google.android.gms:play-services:7.3.0'
}
PlacesSample - Activity that is using google places API:
package com.sampath.project.project_v2;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.ui.PlacePicker;
public class PlacesSample extends AppCompatActivity {
TextView getLocation;
int PLACE_PICKER_REQUEST = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_places_sample);
getLocation = (TextView)findViewById(R.id.getLocTV);
getLocation.setClickable(true);
getLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
Intent intent;
try {
intent = builder.build(getApplicationContext());
startActivityForResult(intent, PLACE_PICKER_REQUEST);
System.out.println("start activity for result");
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_places_sample, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("onActivityResult");
if (requestCode == PLACE_PICKER_REQUEST) {
if (resultCode == RESULT_OK) {
Place place = PlacePicker.getPlace(data, this);
String toastMsg = String.format("Place: %s", place.getName());
Toast.makeText(this, toastMsg, Toast.LENGTH_LONG).show();
}
}
}
}
Logcat:
05-05 23:38:30.593 21408-21408/com.sampath.project.project_v2 I/Timeline﹕ Timeline: Activity_idle id: android.os.BinderProxy#17e945c6 time:628772943
05-05 23:38:30.598 21408-21408/com.sampath.project.project_v2 I/Timeline﹕ Timeline: Activity_idle id: android.os.BinderProxy#17e945c6 time:628772948
05-05 23:38:31.517 21408-21408/com.sampath.project.project_v2 I/Timeline﹕ Timeline: Activity_launch_request id:com.sampath.project.project_v2 time:628773867
05-05 23:38:31.527 21408-21408/com.sampath.project.project_v2 W/ResourceType﹕ For resource 0x01030224, entry index(548) is beyond type entryCount(9)
05-05 23:38:31.527 21408-21408/com.sampath.project.project_v2 W/ResourceType﹕ For resource 0x01030224, entry index(548) is beyond type entryCount(9)
05-05 23:38:31.636 21408-21408/com.sampath.project.project_v2 I/Timeline﹕ Timeline: Activity_idle id: android.os.BinderProxy#2daadb0a time:628773986
05-05 23:38:33.869 21408-21408/com.sampath.project.project_v2 I/System.out﹕ start activity for result
05-05 23:38:34.227 21408-21408/com.sampath.project.project_v2 I/System.out﹕ onActivityResult
05-05 23:38:34.235 21408-21408/com.sampath.project.project_v2 I/Timeline﹕ Timeline: Activity_idle id: android.os.BinderProxy#2daadb0a time:628776586
Francois Wouts' solutions helped answer this. Thank you Francois...
I searched the logs with keyword 'Places' and found that Places API was indeed throwing an exception. It expected the com.google.android.geo.API_KEY within the <application> tags in the Manifest.xml.
I had changed to com.google.android.geo.API_KEY in the <activity> tag and not the one in the <application> tag.
Now changed to com.google.android.geo.API_KEY and removed the same lines from <activity> tag, and got it working. Feel like an idiot for not working this out by myself..
The meta-data tag should read android:name="com.google.android.geo.API_KEY"
It should be within the <application> tag in the Manifest.
Have you double checked that your API key is associated with your application (package name and SHA-1 fingerprint of your app's certificate) in the Developer Console?
You can find instructions at Signup and API Keys. Make sure to set it up for both your debug and your release certificates.
I hope that helps!
I was having the same issue. Make sure you enable Google Places API for Android and not just Places API in the Developer Console. "Places API for Android" will not show up under APIs & Auth/APIs because it isn’t a popular API (yet). You will have to search for it using the API search box.
In manifest file com.google.android.geo.api_key and com.google.android.maps.v2.API_KEY shouldnot be same.
go to https://console.developers.google.com/project
login and follow these steps to get key for placepicker places.
create or choose existing > use google apis > Google Places API for Android > enable > credentials in left menu > add credentials > api key > android key > create > copy key.
paste your key at manifest "com.google.android.geo.api_key"
Note : there is a limit of 1000 requests per day for google places api. after you have to pay money. Better to avoid PlacePicker.
In my case there was conflict of APIs. I have added google-service.json file which also had API key and I generated new key for Maps. So place picker was closing immediately.
Solution :
Use single API key which is in google-service.json file
Enable "Places SDK for Android" feature for your Google Cloud Platform project (with same name as in Firebase project , don't use different project. You will find same name project as you are using in Firebase)
Put SHA1 Application Restriction for android app (Recommended)
Check if you have placed following code in Application tag only
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="API_KEY" />
This issue made me crazy as well, there are so many issues regarding exactly this problem, but no one was helpful for me. At the end, I figured out that there are different Google Places APIs especially for Android. Consequently, the API-Key that I was using was simply for the non-Android version.
Generate your key using this link
https://developers.google.com/places/android-api/signup
May be you forgot to add your machine SHA key to the Google Maps Console. Faced same issue, Added my SHA Key to the console, it started working fine.
I filling out the Consent screen in APIs & Auth of the console and its working fine. Check the screen shot.
It was strange that it was a credentials problem for me. It works even without a warning in debugging mode but when i use released version of my app it just doesnt work (i have registered my release and debug sha1 keys) So i removed all restrictions and now its working.
Add compile 'com.google.android.gms:play-services-location:8.1.0' in gradle
I'll just drop this here, maybe it helps someone in the future.
For me, using the wrong Api key caused the crash, even though it worked fine in the past.
I had to use the second key (the one that is auto-created by Google services for Android) instead of the first one which i created.
In my case when I changed current API key with the one which is in google-service.json, it resolved the problem.
In google-services.json:
"api_key": [
{
"current_key": "PASTE THIS API KEY TO THE MANIFEST"
}
]
The PlacePicker is now officially deprecated.
I'm trying to complete the Udacity Advanced Android App Development course and running into the same issue.
https://developers.google.com/places/android-sdk/client-migration#place-picker-deprecation says that
The Place Picker was deprecated on January 29, 2019. It was turned off
on July 29, 2019, and is no longer available. Continued use will
result in an error message. The new SDK does not support the Place
Picker.
Cross-posting to https://github.com/googlemaps/android-places-demos/issues/2
The PlacePicker is now officially deprecated.
Try this library. Light weight and similar to placepicker with some additional features.
https://github.com/BilalSiddiqui/AddressPicker
In my case I had not provided google with my billing account details so the api was was disabled even after enabling it.
If this is also the case for you, add the billing account in the google cloud console and finally you will be able to do it.
I've been strugling with this problem about week now. Been searching similar topics about this but still can't resolve my problem.
The Prolem is that when i'm trying to run my program on Polar m600 wear or wear emulator (Android V 7.1.1 and API25) they'r giving me this message "Google Play services out of date. Requires 11011000 but found 10289574".
I've followed the "Getting the Last Known Location" part in the android developer site. (Link for the site https://developer.android.com/training/location/retrieve-current.html#play-services)
Here's my Mainactivity code which i'm using
public class MainActivity extends Activity {
private FusedLocationProviderClient mFusedLocationClient;
public Location mLastLocation;
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}
});
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
mLastLocation = location;
Log.d("Location is:",""+mLastLocation);
if (location != null) {
}
}
});
}
}
Here's my manifest.xml`
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#android:style/Theme.DeviceDefault">
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And last but not least my build.gradle
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "ims.fhj.at.testnavigators"
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.android.support:wearable:2.0.3'
compile 'com.google.android.gms:play-services-wearable:11.0.1'
compile 'com.google.android.gms:play-services:11.0.1'}
Create emulator Nexus 5x with Android version O - api 26 - x86 or Android version Nougat - api 24 - x86
Then click on the 3 dots in the emulator and this will open the extanded window, there click on Google Play + update. And that will update Google Play Services to the latest update thats 11.0.55 today.
You have to downgrade the API in wearable gradle file.
The problem is that your device doesn't have up-to-date Google Play Services application.
To fix it change into this:
compile 'com.google.android.gms:play-services-wearable:10.0.0'
compile 'com.google.android.gms:play-services:10.0.0'
My solution is super weird:
Goto Settings -> Apps -> System Apps -> Google Play Store
My version was 10xxxxx which is weird because my watch updated on boot. So, I clicked Remove Update and the version changed to 11xxxxxx.
The problem here is the mismatch of google play services (version) on emulator and gradle file.
It can be solved by two ways:
Remove the mismatch by downgrading the version of google play services
(version) in gradle file to the Google Play Services (version) of the emulator.
Upgrade the Google Play Services on the emulator.
As String wrote the Play Services are not updated on the device.
Unfortunately In a WearOS world it might be that the Play Services are up-to date, but
they are simply not available on the wearables. In that case you can use following methods to react:
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int result = apiAvailability.isGooglePlayServicesAvailable(this);
if (result != ConnectionResult.SUCCESS) {
...
} else {
apiAvailability.getErrorDialog(this, result, REQUEST_CODE,this).show();
}
This has been an ongoing issue with Wear for years (see for example Android Wear Google Play Services).
The best solution seems to be to not use the latest Play Services release. One option is to find a minimum version that seems to cover your targeted production devices; in your case, this sounds like something in the 10.2 range. Alternatively, pick the lowest release that includes all the functionality you need (I personally am using 9.8.0).
For reference, here is the Play Services release history: https://developers.google.com/android/guides/releases
Sometimes this error my occur when you pass the wrong web-client-id value
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(**web-client-id here**)
.requestEmail()
.build()
Use the value in the OAuth client id section indicated Web client (auto created by google service
You have to upgrade Google Play Services and APIs for the image your emulator is using. Check out this answer, worked out for me (Android Studio 3.1): https://stackoverflow.com/a/49751932/2292056
At the moment I'm trying to implement Google Play Games Services Sign In to my android app. I already had a lot of trouble so far, but it seems I', coming closer to it actually working.
The Problem:
When i press login, the sign-in function returns the following error:
02-18 12:31:51.122 5524-21263/? W/Auth: [GetToken] GetToken failed with status code: UNREGISTERED_ON_API_CONSOLE
02-18 12:31:51.128 5206-5723/? E/TokenRequestor: You have wrong OAuth2 related configurations, please check. Detailed error: UNREGISTERED_ON_API_CONSOLE
02-18 12:31:51.144 5206-32272/? W/GamesServiceBroker: Client connected with SDK 8487000, Services 10298230, and Games 39080030
What I've done so far:
I tried to follow the documentation as good as possible, but either I'm doing something wrong or it is kind of a mess. I guess somewhere, i made a mistake.
My Manifest file includes this:
<meta-data android:name="com.google.android.gms.games.APP_ID"
android:value="#string/app_id" />
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version"/>
I have a games-ids.xml file including the App-ID and ID's for highscores and achievements.
My gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.duke.privatpc.quiztest"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':BaseGameUtils')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
This includes the BaseGameUtils downloaded from the Getting Started Page.
I set up the Game at the Google Play Developer Console and added the created App-ID.
I always used my own keystore for creating the apk and also for creating the App-ID. Is there any need to use the debug.keystore at any point?
As you can see here, the SHA1 are identical and the correct APP-ID is shown.
APK SHA1
Developer Console SHA1
I honestly have no idea what I'm doing wrong. I also activated testing and entered my email adress.
Also, absolutely nothing happens when clicking my sign-in button. There is no Google Overlay popping up, I'm not sure if this is already weird?
I hope someone can help me, as I didn't find any questions that could help me and it's getting a bit frustrating for an amateur-programmer like me.
Thanks!
Where did you create the OAuth 2.0 client for your app? From your screenshot it seems that this is the entry in the Google API console.
Did you also create an entry in the Game services section in the Google Play Developer console (see step 2 in the Google documentation)? I had big problems with my current game, because I created the OAuth 2.0 client manually in the Google API console and not in the Google Play Developer console and the OAuth 2.0 IDs in both consoles didn't match. According to a video from Google Developers OAuth 2.0 clients should only be created in the Google Play Developer console. I wrote more about what I did wrong in this post.
I'm currently trying out the Firebase analytics suit, but, i have faced one small issue, my app is distributed on both google play and amazon store (which doesn't support google play services), so for the amazon flavor i want to remove the dependency to Firebase (which i already know how to do), but, i also need to remove the Firebase plugin, so that it doesn't throw an exception while building.
This is what i have as far now:
productFlavors {
google {
applicationId 'google app id'
}
amazon {
applicationId 'amazon app id'
}
}
dependencies {
googleCompile 'com.google.firebase:firebase-analytics:9.0.0'
amazonCompile 'com.amazonaws:aws-android-sdk-mobileanalytics:2.2.12'
amazonCompile('com.crashlytics.sdk.android:crashlytics:2.5.1#aar') {
transitive = true;
}
}
apply plugin: 'com.google.gms.google-services'
But, i need to remove the plugin only if is the amazon flavor.
Is this even possible? Or at least is there something close that i can try ?
UPDATE:
As per Steve request, i went and try the version with Firebase on my Amazon Kindle tablets and it does work even thou there's no Google Play Services installed on them.
As per Steve's answer Firebase analytics works even without Google
play services. But we still can disable google services plugin for
flavors.
Try add code like this:
apply plugin: 'com.google.gms.google-services'
android.applicationVariants.all { variant ->
if (!variant.name.contains("flavorName")) {
project.tasks.each { t ->
if (t.name.contains("GoogleServices")) {
// Remove google services plugin
variant.getVariantData().resourceGenTask.getTaskDependencies().values.remove(t);
// For latest gradle plugin use this instead
// variant.getVariantData().taskContainer.sourceGenTask.getTaskDependencies().getDependencies().remove(t)
}
}
}
}
Here I disable google services for all flavors which their name
doesn't contains "flavorName". You should modify the conditions to fit
your requirement. And notice that this should be added after
apply plugin: 'com.google.gms.google-services'. Hope it helps.
I finally got a version to work with new gradle. Tested with gradle 4.6, build tools 3.0.1, google-services plugin 3.1.1
apply plugin: 'com.google.gms.google-services'
android.applicationVariants.all { variant ->
if (variant.name == 'someVariantNameYouDontwantFirebase') {
project.tasks.getByName('process' + variant.name.capitalize() + 'GoogleServices').enabled = false
}
}
Although Firebase does not officially support devices without Google Play services, Analytics should in fact work on such devices and so you may not actually need to disable Firebase (or remove the plugin) in your Amazon build. Have you tried it yet?
It's possible that, because some Google Play Services libraries still need to be included in your firebase-free flavor, that some firebase related entries end up in the final merged AndroidManifest.xml.
So, if, in addition to removing the gradle tasks which were added by the Google Services plugin (as described in Junyue Cao's answer), you want to remove Firebase related receiver, service, provider, uses-permission or other tags from the final merged AndroidManifest, you can add node markers to the AndroidManifest.xml located in the app's flavor, build config, or build variant subdirectory.
If the node markers are set to "remove", then the corresponding receiver, service, provider, uses-permission tags will not be present in the final merged AndroidManifest.xml.
For example, here's what you might add to the AndroidManifest.xml in a project's hypothetical 'nofirebase' flavor source dir (app/src/nofirebase/):
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
tools:node="remove" />
<receiver
android:name="com.google.android.gms.measurement.AppMeasurementReceiver"
tools:node="remove" />
<receiver
android:name="com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver"
tools:node="remove" />
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
tools:node="remove" >
</receiver>
<service
android:name="com.google.android.gms.measurement.AppMeasurementService"
tools:node="remove" />
<service
android:name="com.google.firebase.iid.FirebaseInstanceIdService"
tools:node="remove"/>
<provider
android:name="com.google.firebase.provider.FirebaseInitProvider"
android:authorities="com.you.yourapp.firebaseinitprovider"
tools:node="remove"/>
With answers above I was receiving an error that task doesn't exist (?it was generated during build?). What worked for me was to simply ask tasks to correct themselves. In my case I was disabling Fabric on UAT builds.
tasks.all {
if (it.name.contains("Uat") && (
it.name.contains("GoogleServices") ||
it.name.contains("fabric"))
){
it.enabled = false
}
}