Android Tutorial (old) Google Maps Android v2 tutorial

Status
Not open for further replies.
If you are using B4A v5.80+ then please follow this tutorial: https://www.b4x.com/android/forum/threads/google-maps.63930/#post-404386

GoogleMaps library requires v2.50 or above.

GoogleMaps library allows you to add Google maps to your application. This library requires Android 3+ and will only work on devices with Google Play service.

This tutorial will cover the configuration steps required for showing a map.

1. Download Google Play services - From the IDE choose Run AVD Manager and then choose Tools - SDK Manager. Select Google Play services under the Extras node and install it:

SS-2012-12-18_18.28.04.png


2. Copy google-play-services.jar to the libraries folder - This file is available under:
C:\<android sdk>\extras\google\google_play_services\libproject\google-play-services_lib\libs (ignore the extra space that the forum script insists on adding)
You should copy it to the libraries folder.

2.5. Download the attached library, unzip it and copy to the libraries folder.

3. Find the key signature - Your application must be signed with a private key other than the debug key. After you select a new or existing key file (Tools - Private Sign Key) you should reopen the private key dialog. The signature information will be displayed (increase the dialog size as needed).
The value after SHA1 is required for the next step:

SS-2012-12-18_18.11.34.png


4. Create an API project - Follow these steps and create an API project.
You should follow the steps under "Creating an API Project" and "Obtaining an API key".

Tips:
- Make sure to select "Google Maps Android API v2" in the services list and not one of the other similar services.
- Under "Simple API Access" you should select "Key for Android apps (with certificates".

5. Add the following code to the manifest editor:
B4X:
AddManifestText( <permission
          android:name="$PACKAGE$.permission.MAPS_RECEIVE"
          android:protectionLevel="signature"/>
      <uses-feature android:glEsVersion="0x00020000" android:required="true"/>)

AddApplicationText(<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="AIzaSyCzspmxxxxxxxxxxxxx"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"
    />)
AddPermission(android.permission.ACCESS_NETWORK_STATE)
You should replace the value after android:value with the key you received in the previous step.

6. Add an #AdditionalRes attribute to the main activity:

You should add a reference to Google play resources by adding the following line:
B4X:
#AdditionalRes: <google-play-services res folder>, com.google.android.gms
For example:

#AdditionalRes: C:\android-sdk-windows\extras\google\google_play_services\libproject\google-play-services_lib\res, com.google.android.gms

Run the following code:
B4X:
'Activity module
Sub Process_Globals

End Sub

Sub Globals
   Dim mFragment As MapFragment
   Dim gmap As GoogleMap
   Dim MapPanel As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
   MapPanel.Initialize("")
   Activity.AddView(MapPanel, 0, 0, 100%x, 100%y)
   If mFragment.IsGooglePlayServicesAvailable = False Then
      ToastMessageShow("Google Play services not available.", True)
   Else
      mFragment.Initialize("Map", MapPanel)
   End If
End Sub
Sub Map_Ready
   Log("map ready")
   gmap = mFragment.GetMap
   If gmap.IsInitialized = False Then
      ToastMessageShow("Error initializing map.", True)
   Else
      gmap.AddMarker(36, 15, "Hello!!!")
      Dim cp As CameraPosition
      cp.Initialize(36, 15, gmap.CameraPosition.Zoom)
      gmap.AnimateCamera(cp)
   End If
End Sub

You should see:

SS-2012-12-18_18.25.14.png


If you see a "white map" then there is most probably a mismatch between the: package name, sign key and the API key (from the manifest editor).

Google documentation: https://developers.google.com/maps/documentation/android/intro
Note that there is a required attribution which you must include in your app (see above link). You can get the string by calling MapFragment.GetOpenSourceSoftwareLicenseInfo.

V1.01: Fixes a bug in AddMarker2.
 

Attachments

  • GoogleMaps.zip
    17.8 KB · Views: 11,594
Last edited:

warwound

Expert
Licensed User
Longtime User
The native android (java) GoogleMaps library has been updated many times since this thread was first started.

It is no longer a requirement to include either of these two manifest entries in order to use GoogleMaps:
  • Feb & May 2013 - OpenGL ES 2.0 feature requirement is no longer required to be included in AndroidManifest. Note: OpenGL ES 2.0 is still required for Maps to function.
  • July 2013 - The MAPS_RECEIVE permission is no longer required. You can remove this permission from your manifest.

More info can be found here: https://developers.google.com/maps/documentation/android/releases.

Martin.
 

M6SOFT

Member
Licensed User
Longtime User
With customtileprovider
I have the same problem. Tested on sIII and nexus7. It's very strange. On my devices sequence looks like this:
1. First are painted my tiles on white (chess) background
2. In a moment all map view is covered by black squares
MAP_TYPE_NORMAL:
gm_map.png
MAP_TYPE_NONE:
gm_none.png
 

scrat

Active Member
Licensed User
Longtime User
Yes it's very strange !

in some location this problem does not exist.
I have tried the "Seoul" position and no problem even with a zoom 17 !
 

Ohanian

Active Member
Licensed User
Longtime User
Hi,

Is there any way to detect click on a polygon?
 

warwound

Expert
Licensed User
Longtime User
MapsForgeTileProvider enables you to render a MapsForge map database file on a GoogleMap.

This example project requires GoogleMapsExtras, MapsForgeTileProvider and the latest version of AHPreferenceActivity.

Here's the code:

B4X:
Sub Process_Globals
   Dim LastCameraPosition As CameraPosition
   Dim PreferenceManager1 As AHPreferenceManager
   Dim PreferenceScreen1 As AHPreferenceScreen
End Sub

Sub Globals
  Dim GoogleMap1 As GoogleMap
   Dim LastMapLatitude As Double
   Dim LastMapLongitude As Double
   Dim LastMapZoom As Float
   Dim MapDatabaseName As String="kings_lynn.map"
  Dim MapFragment1 As MapFragment
  Dim MapPanel As Panel
   Dim MapsForgeTileOverlay As TileOverlay
   Dim MapsForgeTileProvider1 As MapsForgeTileProvider
   Dim TextScale As Float
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("Main")
   Activity.AddMenuItem3("Settings", "Settings", Null, True)
 
  If MapFragment1.IsGooglePlayServicesAvailable = False Then
  ToastMessageShow("Google Play services not available", True)
  Else
     If FirstTime Then
       If Not(File.Exists(File.DirDefaultExternal, MapDatabaseName)) Then
         '   copy the mapsforge database to default package directory
         File.Copy(File.DirAssets, MapDatabaseName, File.DirDefaultExternal, MapDatabaseName)
       End If
       CreatePreferences
     End If
  MapFragment1.Initialize("MapFragment1", MapPanel)
  End If
End Sub

Sub Activity_Resume
   '   check if we are returning to this Activity from the AHPreferenceActivity and a preference has been changed
   Dim UpdatedKeys As List=PreferenceManager1.GetUpdatedKeys
   If GoogleMap1.IsInitialized AND UpdatedKeys.Size>0 Then
     '   1 or more preference values have been updated
     If UpdatedKeys.IndexOf("MapType")<>-1 Then
       '   MapType preference has been updated
       Dim MapType As Int=PreferenceManager1.GetString("MapType")
       If MapType<>GoogleMap1.MapType Then
         GoogleMap1.MapType=MapType
         '   if the default or saved map type is MAP_TYPE_NONE we will display mapsforge tiles
         '   otherwise we'll display a built in visible google map type
         '   hide the mapsforge tiles if the default or saved map type is a built in visible google map type
         If MapType=GoogleMap1.MAP_TYPE_NONE Then
           MapsForgeTileOverlay.Visible=True
         Else
           MapsForgeTileOverlay.Visible=False
         End If
       End If
     End If
     If UpdatedKeys.IndexOf("TextScale")<>-1 Then
       '   TextScale preference has been updated
       Dim NewTextScale As Float=PreferenceManager1.GetString("TextScale")
       If NewTextScale<>TextScale Then
         TextScale=NewTextScale
         MapsForgeTileProvider1.SetTextScale(TextScale)
         '   clear existing tiles so new tiles are rendered with the new text scale
         MapsForgeTileOverlay.ClearTileCache
       End If
     End If
   End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   If GoogleMap1.IsInitialized Then
     '   save the CameraPosition, map center and zoom level
     LastCameraPosition=GoogleMap1.CameraPosition
     PreferenceManager1.SetString("Latitude", GoogleMap1.CameraPosition.Target.Latitude)
     PreferenceManager1.SetString("Longitude", GoogleMap1.CameraPosition.Target.Longitude)
     PreferenceManager1.SetString("Zoom", GoogleMap1.CameraPosition.Zoom)
   End If
End Sub

Sub BitmapToByteArray(Bitmap1 As Bitmap) As Byte()
   Dim OutputStream1 As OutputStream
   Dim ByteArray1() As Byte
   OutputStream1.InitializeToBytesArray(1)
   Bitmap1.WriteToStream(OutputStream1, 100, "PNG")
   ByteArray1 = OutputStream1.ToBytesArray
   OutputStream1.Close
   Return ByteArray1
End Sub

Sub CreatePreferences
   '   note i've added a line to the manifest to include the AHPreferenceActivity
   '   version 1.04+ of AHPreferenceActivity is required
   PreferenceScreen1.Initialize("Settings", "")
 
   Dim Category1 As AHPreferenceCategory
   Category1.Initialize("Map")
 
   '   MapTypes is a b4a Map object whose keys are String representations of Integer MapTypes and values are String names of the MapType
   '   (the AHPreferenceActivity handles only String and Boolean types so we must use Strings for the Integer MapType values)
   Dim MapTypes As Map
   MapTypes.Initialize
   Dim StringValues(5) As String=Array As String(GoogleMap1.MAP_TYPE_HYBRID, GoogleMap1.MAP_TYPE_NONE, GoogleMap1.MAP_TYPE_NORMAL, GoogleMap1.MAP_TYPE_SATELLITE, GoogleMap1.MAP_TYPE_TERRAIN)
   MapTypes.Put(StringValues(0), "Hybrid")
   MapTypes.Put(StringValues(1), "MapsForge")
   MapTypes.Put(StringValues(2), "Normal")
   MapTypes.Put(StringValues(3), "Satellite")
   MapTypes.Put(StringValues(4), "Terrain")
   Category1.AddList2("MapType", "Map Type", "Select source of map tiles", StringValues(1), "", MapTypes)
 
   '   12290 is INPUT_TYPE_DECIMAL_NUMBERS
   Category1.AddEditText2("TextScale", "Text Scale", "How much to scale the text on rendered tiles", "1.0", 12290, False, True, "")
 
   PreferenceScreen1.AddPreferenceCategory(Category1)
 
   If PreferenceManager1.GetAll.Size = 0 Then
     PreferenceManager1.SetString("MapType", StringValues(1))
     PreferenceManager1.SetString("TextScale", "1.0")
   
     '   i've used the PreferenceManager to save map center and zoom
     '   these preferences aren't exposed in the AHPreferenceActivity
   
     '   set the default map center and zoom
     PreferenceManager1.SetString("Latitude", "52.75619")
     PreferenceManager1.SetString("Longitude", "0.3980")
     PreferenceManager1.SetString("Zoom", "14")
   End If
 
   PreferenceManager1.GetUpdatedKeys
End Sub

Sub MapFragment1_Ready
  Log("MapFragment1_Ready")
  GoogleMap1=MapFragment1.GetMap
  If GoogleMap1.IsInitialized = False Then
  ToastMessageShow("Error initializing map", True)
  Else
     '   get the default or last saved map type
     Dim MapType As Int=PreferenceManager1.GetString("MapType")
     GoogleMap1.MapType=MapType
   
     Dim GoogleMapsExtras1 As GoogleMapsExtras
     Dim NoTileTile As Tile
     Dim TileOverlayOptions1 As TileOverlayOptions
   
     MapsForgeTileProvider1.GetMapsForgeTileProviderOptions.SetMapDatabaseFile(File.DirDefaultExternal, MapDatabaseName)
   
     '   optional - set a tile to be displayed where there are no mapsforge tiles
     NoTileTile.Initialize(256, 256, BitmapToByteArray(LoadBitmap(File.DirAssets, "no_tiles.png")))
     MapsForgeTileProvider1.GetMapsForgeTileProviderOptions.SetNoTileTile(NoTileTile)
   
     '   optional - but in this demo we want to set the default text scale or restore the last text scale
     TextScale=PreferenceManager1.GetString("TextScale")
     MapsForgeTileProvider1.GetMapsForgeTileProviderOptions.SetTextScale(TextScale)
   
     '   the following single line syntax is also possible
     '   MapsForgeTileProvider1.GetMapsForgeTileProviderOptions.SetMapDatabaseFile(File.DirDefaultExternal, MapDatabaseName).SetNoTileTile(NoTileTile).SetTextScale(TextScale)
   
     '   now that we have set the required (and some optional) MapsForgeTileProviderOptions we can call the MapsForgeTileProvider Initialize method
     MapsForgeTileProvider1.Initialize
   
     TileOverlayOptions1.Initialize
     TileOverlayOptions1.SetTileProvider(MapsForgeTileProvider1)
   
     If MapType<>GoogleMap1.MAP_TYPE_NONE Then
       '   if the default or saved map type is MAP_TYPE_NONE we will display mapsforge tiles
       '   otherwise we'll display a built in visible google map type
       '   hide the mapsforge tiles if the default or saved map type is a built in visible google map type
       TileOverlayOptions1.SetVisible(False)
     End If
   
     MapsForgeTileOverlay=GoogleMapsExtras1.AddTileOverlay(GoogleMap1, TileOverlayOptions1)
   
     GoogleMap1.AddMarker(52.75619, 0.3980, "Home Sweet Home")
   
     If LastCameraPosition.IsInitialized Then
       '   restore the last saved CameraPosition
       GoogleMap1.AnimateCamera(LastCameraPosition)
     Else
       '   set the default or last saved map center and zoom level
       LastMapLatitude=PreferenceManager1.GetString("Latitude")
       LastMapLongitude=PreferenceManager1.GetString("Longitude")
       LastMapZoom=PreferenceManager1.GetString("Zoom")
     
       '   center the map on the default or last saved map center and zoom
    Dim CameraPosition1 As CameraPosition
    CameraPosition1.Initialize(LastMapLatitude, LastMapLongitude, LastMapZoom)
    GoogleMap1.AnimateCamera(CameraPosition1)
     End If
   
  End If
End Sub

Sub Settings_Click
   StartActivity(PreferenceScreen1.CreateIntent)
End Sub

The GoogleMap will load centered on my hometown displaying tiles rendered on the fly on the device from Open Street Map data. This is the data in the MapsForge database kings_lynn.map.
Click 'Settings' and you can select any of the other (built in) GoogleMaps MapTypes or the scale at which text on the map is rendered.
The AHPreference library remembers your choice of MapType, text scale, the map center and the map zoom level so when you restart the app it will restore your previous view.

If you pan the map to an area where the MapsForge database has no data then you'll see the 'no tiles tile'.

Enable aeroplane mode on your device and you'll see the MapsForgeTileProvider continues to work perfectly - offline tiles is the key feature of MapsForge.

In order to compile this example you'll need to update the project's package name and choose a valid private sign key.

Once you have the project working you can change the MapsForge database for another.
There's a selection of MapsForge databases available for download from here: http://download.mapsforge.org/maps/.

And if you're feeling adventurous then you can take a look here: http://code.google.com/p/mapsforge/wiki/GettingStartedMapWriter.
Install both Osmosis and the Mapsforge Map-Writer and create your own MapsForge database.

Martin.
 

Attachments

  • MapsForgeTileProvider_demo.zip
    40.7 KB · Views: 610

Powie

Member
Licensed User
Longtime User
I have successfully used this lib and it works like a charme. Anyhow, some Devices reports an error and I have no idea why.

Error:

B4X:
java.lang.NoSuchMethodError: android.app.Activity.getFragmentManager
at anywheresoftware.b4a.objects.MapFragmentWrapper.Initialize(MapFragmentWrapper.java:115)
at com.powie.madb.field._activity_create(field.java:316)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
at com.powie.madb.field.afterFirstLayout(field.java:98)
at com.powie.madb.field.access$100(field.java:16)
at com.powie.madb.field$WaitForLayout.run(field.java:76)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(Native Method)

Devices reported from:

Galaxy S II (GT-I9100)
Galaxy Tab (GT-P1000)
Desire S (saga)
GT-S7500 (GT-S7500)
Galaxy S Advance (GT-I9070P)
Galaxy Ace2 (GT-I8160)
Galaxy S II (GT-I9100)
Desire HD (ace)

For myself I have also access to a HTC Desire HD on which all is fine..... Is it possible that mFragment.IsGooglePlayServicesAvailable reports a false status or anything others?
 

warwound

Expert
Licensed User
Longtime User
java.lang.NoSuchMethodError: android.app.Activity.getFragmentManager

That sounds as if you trying to run the app on devices with android version prior to 3, take a look at the first post in this thread where Erel states:

This library requires Android 3+ and will only work on devices with Google Play service.

Martin.
 

Powie

Member
Licensed User
Longtime User
Thes mean's also, I cannot use mFragment.IsGooglePlayServicesAvailable ?

I have solved this by using Phone Lib for Checking SDKVersion

If Phone.sdkVersion < 12 Then .....
 

marcick

Well-Known Member
Licensed User
Longtime User
Hi,
in which case the googleplay service could be unavailable ?
Which message is correct to show the user in this case ?
Marco
 

warwound

Expert
Licensed User
Longtime User
Hi,
in which case the googleplay service could be unavailable ?

The last update to the Google Play Services depended on the device also updating it's Maps application.
If you compile a b4a project with GoogleMaps using the very latest version of Google Play Services and the device Maps application has not yet been updated to the latest version then the IsGooglePlayServicesAvailable method might return False.

I posted some info here: http://www.b4x.com/android/forum/threads/google-play-services-resources-not-found.33091/#post-199964
You can see that your app might also crash if you use the latest version of Google Play Services and don't update your app to include the new 'google_play_services_version' integer resource.

IsGooglePlayServicesAvailable was returning False for me on an old HTC device when i made that post, since then Play Store offered a Maps application update and now IsGooglePlayServicesAvailable returns True.

So the answer to your question very much depends on:
  • The version of the Google Play Services library you are compiling with.
  • The version of the Maps application installed on the device.

Martin.
 

marcick

Well-Known Member
Licensed User
Longtime User
.... everyday everyting is more complicated .....
If I compile the app with the latest GooglePlayLibrary (should be 12, correct ?) and use your last update of GoogleMapExtra (1.52) do I still have to modify the manifest and copy some resources as you explain in the post above ?
 

mujeeb74

Member
Licensed User
Longtime User
hi,

Every time i compile any example i have follwing error:

java.lang.IllegalStateException: The meta-data tag in your app's AndroidManifest.xml does not have the right value. Expected 4030500 but found 0. You must have the following declaration within the <application> element: <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

and I don't know how to fix it
 

warwound

Expert
Licensed User
Longtime User
hi,

Every time i compile any example i have follwing error:

java.lang.IllegalStateException: The meta-data tag in your app's AndroidManifest.xml does not have the right value. Expected 4030500 but found 0. You must have the following declaration within the <application> element: <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

and I don't know how to fix it

Look here for the fix: http://www.b4x.com/android/forum/threads/google-play-services-resources-not-found.33091/#post-199964

Martin.
 

warwound

Expert
Licensed User
Longtime User
The latest version of Google Play Service is version 13.

This is what i'd consider to be the bare minimum steps required in order to use version 13:
  • Copy the file version.xml from the android SDK to your project's Objects/res/values folder. Create the 'values' folder is it does not exist. Mark version.xml as read-only.
    version.xml can be found in the android SDK at a path similar to this:
    android-sdk/extras/google/google_play_services/libproject/google-play-services_lib/res/values/version.xml
  • Update your manifest adding these entries if they do not already exist:
    • AddApplicationText(<meta-data
      android:name="com.google.android.gms.version"
      android:value="@integer/google_play_services_version" />)
    • AddPermission(android.permission.INTERNET)
    • AddPermission(android.permission.ACCESS_NETWORK_STATE)
    • AddPermission(com.google.android.providers.gsf.permission.READ_GSERVICES)
    • AddPermission(android.permission.WRITE_EXTERNAL_STORAGE)

Now, as long as your app users have the latest version of Google Play Services installed on their device, i think your app will work.
Erel stated above that:
You can ask the user to install Google Play Services. It is available in Google Play.
I've searched Play Store but found no Google Play Services available.
I assumed that Google Play Services is like an 'automatic update' that can't be manually installed or updated, but if already installed on a device it will update itself to the latest version when required.

One last thing to consider - do you want to copy just version.xml from the android SDK to your project or do you want to copy all of the resources from android-sdk/extras/google/google_play_services/libproject/google-play-services_lib/res to your project's Objects/res folder?

Although i think you do not need all of these resources - only version.xml is required i think - you might see various 'resource not found' errors in the unfiltered log if you do not copy all of the resources from the SDK to your project.

All of these SDK resources look to be around 484KBs in size, if you include them in your project:
  • They will be compressed and occupy less space then 484KBs, but still increase the size of your compiled APK.
  • The log will no longer show lots of 'resource not found' errors.

All or many of these resources are not required by the b4a GoogleMaps library - your option is a larger APK and no errors in the log or an APK not increased in size and errors in the log.

Martin.
 

mujeeb74

Member
Licensed User
Longtime User
I use following code:

Dim m As Marker
m = gmap.AddMarker3(37, 16, "2",LoadBitmap(File.DirAssets,"red.png"))

and I include red.png (24x24) in file tab
 
Status
Not open for further replies.
Top