Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
Creating a map plugin - How hard would it be? — Gideros Forum

Creating a map plugin - How hard would it be?

PaulHPaulH Member
edited June 2014 in Plugins
I've used Google Maps in a native Android app, and used a similar map view in an iOS native app, and I've integrated a couple of plugins into a Gideros app. I've never created a Gideros plugin.

That said, how monumental a task would it be to create a mapping plugin? Has anyone explored it? I'd want a screen that would allow users to zoom and pan, show crosshairs or some other marker of a selected position, and maybe overlay icons at selected coordinates. I'm considering developing this plugin, and I'm trying to get a sense for how much work I may be looking at.

I see others have asked about such a plugin, and I'm contemplating trying to create it. Has anyone else considered creating such a plugin?

I'd be interested to hear from anyone who's worked on custom plugins, but especially those with a common interface between Android and iOS. Any thoughts?

PaulH
«1

Comments

  • Hi @PaulH
    I tried with this link
    http://giderosmobile.com/forum/discussion/1025/step-by-step-how-to-write-a-c-plugin-and-deploy-it-to-the-desktop-windows-player/p1

    but still I couldn't even testing it with Android. I know there are a few guidelines to android here
    http://giderosmobile.com/forum/discussion/830/creating-a-simple-android-plugin/p1

    But I believe that @ar2rsawseen can give you better information about your question because, he has developped some plugin in Gideros Labs, both iOS and Android
  • ar2rsawseenar2rsawseen Maintainer
    edited June 2014
    The way I'd do it is:
    1) you create classes with static methods (ObjectiveC and Java) to manipulate all the stuff in the maps you need
    2) then you create a C++ class to wrap it (through JNI for Android and .mm file for ObjectiveC)
    3) then I usually create plain C interface for this class, so it would be independent of the language
    4) and then I write bindings to the Lua for this C interface

    That is about it. Some source examples are provided in the Gideros installation directory (Google billing plugin is a great source to start with, the one I used to learn plugin development)

    But if you have any specific questions, I can help and answer :)

    I know that Maps plugin was requested couple of times, and I would really want to promise to make one soon, but for now there are a lots of things I need to do :(

    I was actually again thinking on creating common Maps interface, because there are Goolge maps for Android, then Apple maps for IOS, then Amazon maps for kindle and then Nokia Maps for Nokia X. So you see the point :)
  • PaulHPaulH Member
    Thanks! That's very helpful. I'll start with a closer look at the billing and other plugins.

    PaulH
  • I'm currently trying to learn enough about plugins to develop one for mapping. I need a common map interface for Android and iOS. I've used maps in native apps on both platforms, so that part is not a problem, but the learning curve for this sort of plugin development is considerable. I'll keep at it.

    Unless...

    Ar2rsawseen, you've mentioned before you've considered developing this plugin. I'm sure you could develop this one in a fraction of the time it would take me. I'd be willing to pay for this plugin if you'd consider taking it on.

    Any chance of that?

    Paul
  • Well, you say native part is not a problem, for me it would most probably be the biggest problem :)

    But we could try to split the work.

    Do you have any idea for Lua interface?
    As in which classes, methods, event would be available on lua side, that would be enough to control Map?
  • That would be great. Yes, I can certainly help the native code that works directly with the map. I'll propose a design for the Lua interface and post it here.

    Thanks for being willing to help with this!

    Paul
  • Here are my initial thoughts on an interface for a common mapping plugin:

    Basically I'd be looking for fairly thin cover over native map functions.

    The bare minimum functionality from my perspective is the ability to position a map by latitude & longitude, to set the zoom level, to switch between different map styles (street vs satellite), to add markers, and handle touch events. For the markers the bare minimum functionality would be to specify a label or title for each, and handle touch events.

    It might be helpful, though not necessarily a required feature, for a map to use the Sprite base class, or at least support addChild() like a Sprite. That would make it possible to use Sprites to implement custom map markers or overlays in lots of ways. If that’s feasible, it might not be necessary to support the markers native to the underlying map. I suppose another option is to have the Map be only that (not a sprite or container for sprites) and leave it to users to create a View who’s children would include one map and any number of Sprites that overlap it.

    The Map class would support these methods:

    function Map:init(latitude, longitude, zoom, witdth, height, positionX, positionY)

    function Map:setPosition(positionX, positionY) – position the Map on the screen, relative to its parent, whether or not Map uses Sprite as a base class

    function Map:setType(mapType) -- support "normal", "satellite", "terrain", "hybrid" (satellite with roads overlaid)

    function Map:setCenter(latitude, longitude) -- move the map to view the specified coordinates

    function Map:setZoom(zoomLevel) -- control the zoom level of the map, units TBD

    function Map:setLocationEnabled(locationEnabled) -- at least for Android, enable the default “go to my location” button overlaid on the map

    function Map:onMapClickListener( event handler...)-- handle touches on the map, i.e. for selecting a location

    function Map:addMarker(marker) -- add a default style marker to the map – see below

    function Map:clear() -- remove all markers

    function Map:addEventListener(eventType, eventHandlerFunction) -- Support eventType "move", detecting when the map has been moved manually. Not strictly necessary, but useful when supporting navigation, or any scenario where you might program the app to move and/or zoom the map automatically, unless the user has manually moved it.

    function Map:getLocationPosition(latitude, longitude) -- returns x, y of specified location relative to the Map; This would only be necessary if Map supports Sprites as children, in which case this would be used to position the sprites.

    function Map:getLocation() returns latitude and longitude of center of map

    The MapMarker class, if markers are implements as a cover over native map markers rather than Sprite children of the map, would support these methods:

    function MapMarker:init(latitude, longitude, title) -- Sets the coordinates and name of a marker

    function MapMarker:setAlpha(alpha) – sets transparency of marker

    function MapMarker:setHue(hue) -- 0 to 360, angle to position on color wheel, from 0 (red) through orange and yellow to green (180) through blue and purple back to red (360.) Some other set of hue values could be used and mapped to platform specific values in the native code.

    function MapMarker:addEventListener(eventType, eventHandlerFunction) -- Support clicks/taps on each marker

    function MapMarker:setId(id) -- A generic ID one could use to associate a specific marker with additional data

    function MapMarker:getId(id) -- A generic ID one could use to associate a specific marker with additional data

    funciton MapMarker:getTitle() -- Returns the title specified in init(). Not strictly necessary if IDs are supported, as the calling code could keep track of the titles of all markers along with any other data specific to each marker that was added.

    function MapMarker:getLocation() -- Returns latitude and longitude specified in init(). Not strictly necessary if IDs are supported, as the calling code could keep track of the coordinates of all markers along with any other data specific to each marker that was added.

    -- Not including functions to alter existing markers. That's probably rarely used, and one can use a function to clear the map and add updated markers if necessary.

    Thoughts?

    Paul

    Likes: antix

    +1 -1 (+1 / -0 )Share on Facebook
  • antixantix Member
    edited February 2016
    I would really like to see this kind of thing in Gideros, I have a few great ideas for map based apps stuck in my head that just cant get out :>

    But I do think you need MapMarker:setTitle() to make it easier to use, and be more complete (every get should be complimented with a set)
  • Agreed - I overlooked that one. I'd say the init should include the parameters that can't be meaningfully defaulted, but even those should have sets & gets.
  • Ok, about Sprite interaction, unfortunately there can be none.
    Sprite is drawn over GL surface, and Map can be either under or over GL surface (if it would be under, we would not see it, so only over).

    So positioning will be absolute, over all screen, but still would count in scale modes and logical dimensions (so 200px width for Shape would be visually the same for map). That is possible.

    One question that I have though, do all platforms (Android and iOS for now) support all these features for Maps?

    So let me try to prepare the Lua part, and then we can try to match it to some native methods :)
  • I believe all of this is possible in both Android and iOS, though the native code will be a bit different. For example, on Android you can use a single function call to do the equivalent of setZoomLevel, where the zoom level is a value from 1 (show a continent or more) to 18 (show a city block or less). On iOS you manage the zoom by creating a Camera object in which you set the eyeCoordinate, centerCoordinate and eyeAltitude. In our case, we'd use the map center coordinates for both the eye and center coordinates, so the camera is looking straight down, as opposed to an oblique view. Increasing the eyeAltitude effectively decreases the zoom level. In the iOS native code we can probably come up with a table or conversion function to find comparable altitude values for each Android zoom level, so the Lua plugin can be used with a common range of values.

    I haven't dealt with markers in iOS yet, but will look into that.

    Do I understand correctly that we won't be able to display any sprite over the top of the map, since the sprites can only appear on a GL surface, and the GL surface can't have a transparent background so we can't put a GL surface over the map to expose both?

    If that's the case, then we can skip the function Map:getLocationPosition(latitude, longitude) which isn't built in to either native map system, and the main reason I thought it would be worth writing was for overlaying sprites over the map. We'll have to support markers strictly through the native methods. It's very straightforward on Android. I'll educate myself further on the iOS side.

    Paul
  • It would be a shame to not be able to place sprites over top of a map.
  • The native method (at least on Android) supports custom icons as markers on a map, though the interface I proposed above doesn't support that. As described above we'd be using the default markers, with control over hue and alpha. I think the interface could be expanded to handle specifying the image file to use for each marker. If it were possible to have a Gl surface over the top of a Map, with transparency to allow the map to show, then we'd have lots of power over markers and overlays, but if I understand ar2rsawseen correctly, it sounds like that won't be possible.

  • hgy29hgy29 Maintainer
    Hi @PaulH, you may also want to consider a pure Lua implementation: http://giderosmobile.com/forum/discussion/comment/40275#Comment_40275

    Likes: antix

    +1 -1 (+1 / -0 )Share on Facebook
  • antixantix Member
    Let us know how you get on if you look at hgy29's LUA based map code.

    In theory a LUA based one would be slower but really how fast does a map thing need to be?
  • ar2rsawseenar2rsawseen Maintainer
    And yes not to be able to place sprites over map, sorry :)
  • hgy29hgy29 Maintainer
    My lua based Map works well, and since it is a gideros Sprite you can overlay what you want on it. The only drawback, which is a big one, is that it fetches tiles directly from some external tile source, and most of map providers aren't too happy with such thing.

    If you don't make a lot of requests it should be fine, otherwise you may need a contract with some map tile provider, or you could set up your own tile server from OpenStreetMap data.
  • PaulHPaulH Member
    I've been checking out Hgy29's solution, and it's really slick. I'm really impressed with the ease of implementation. If I were mapping business locations or events, I'd use it without hesitation. Unfortunately for my purposes, I think I'll need the native map support unless I can find a compatible tile server that supports satellite or satellite/street hybrid maps. The app in question is a tool for fishing, using a map to let people mark fishing spots, or the locations of their catches, etc. Most people use the map in satellite mode, so they can see details of the shorelines, weed beds on the surface, etc. I'm exploring options for tile providers, but I suspect the native map solution may be my only realistic option.
  • hgy29hgy29 Maintainer
    in my main.lua, you could try uncommenting the 'map:setTiuleSource' line and use MapTileSource.GoogleHybrid instead of GoogleRoad.
    Have a look at MapTileSource file :)

    However these tile sources are direct access to google server, largely unofficial way of getting their maps...
  • PaulHPaulH Member
    Very cool - That would work perfectly if it were allowed by Google's terms of service. As I understand it, their policy disallows any use of the tiles that doesn't come through their official API, but I'll read up on it to see if there's any interpretation that might make this OK. I need to be very careful to stay compliant with their terms. The current version of the app in question probably generates around half a million map requests per month in peak season, which makes the other tiles services that support satellite views I've found so far (MapQuest, Here.com, etc.) quite expensive.
  • PaulHPaulH Member
    Google's terms of service to prohibit that kind of access, as expected: "You will not access the Maps API(s) or the Content except through the Service. For example, you must not access map tiles or imagery through interfaces or channels (including undocumented Google interfaces) other than the Maps API(s)." A substantial share of my income comes from the app stores, so I need to stay in good standing with Google. As much as I'd love to use your pure Java implementation, I'll have to stick with the official API.
  • antixantix Member
    @PaulH I suppose that goes for any app really if you don;t want to get the app kicked from the play store you will have to use the google API :(
  • PaulHPaulH Member
    I think so, yes. I'd even worry that by violating their TOS one could get ones whole developer account revoked, losing all ones apps. For those making a living from apps, it's not worth the risk. But... it sure would be a lot easier to integrate maps that way.
  • antixantix Member
    Darn google and their pesky control, I thought apple were the control freaks :D
  • Although I haven't made an iOS mapkit plugin for Gideros, I did quite successfully use a HTML WebKit frame for a hybrid Gideros/WebKit series of enterprise apps that leverages the Leaflet API for mapping. It still happily works under iOS 9 although the app hasn't been updated since 2013.

    You can check an example of an iOS app here:
    Open Studios by Ian Chia
    https://appsto.re/au/tvSjx.i

    Happy to share the code if it would be useful.

    Best,

    - Ian

    Likes: antix

    +1 -1 (+1 / -0 )Share on Facebook
  • PaulHPaulH Member
    Thanks for sharing that, but it looks like the Leaflet API is another that relies on a third-party map tile server. In the Leaflet documentation they suggest Mapbox, which is another one that's free for light use, but quite expensive (USD 500 per month) if your app will make hundreds of thousands of requests per month.

    I'm going to continue to pursue the native map APIs. My next step will be to try to work on the Android native Java to setup a map with hardcoded values. Hopefully that will make it fairly straightforward to connect the parameters coming in through the plugin framework.

    Paul
  • PaulHPaulH Member
    Progress... I've taken the Android project exported from a Gideros project and made the minimal changes necessary to overlay a working Google Map on it. Next I'll add the functions for things like positioning and zooming the map, and split as much of it as possible out of the main activity java file. Some changes will be necessary there, since the main activity must extend FragmentActivity rather than the standard Activity, but I'll document exactly what changes are needed. Once the Android native code is done, I'll try to do the same for iOS. Then hopefully making a plugin over that native code will be fairly straightforward for ar2rsawseen. =)

    Likes: keszegh, totebo, antix

    +1 -1 (+3 / -0 )Share on Facebook
  • PaulHPaulH Member
    I propose a change to the interface to avoid using listeners or other callbacks outside the native layer (Java for Android.) I think this will be simpler to implement and use, given the number of layers between the Lua and the native code. Rather than have map or marker event listeners, I'm proposing having functions that can be called to check for moves or clicks since the previous call. This way I think the mapping of Lua functions to native functions can be one-to-one. Hopefully this will make the plugin layer fairly straightforward.

    Also I'm proposing eliminating the Marker as a separate class. Instead I've added functions to manipulate markers directly within the Map class. Adding a marker returns an index, which can be used to handle clicks, get/set the title and coordinates, and set the hue and alpha.

    Lastly I've added show/hide functions, since we will of course need to control when the map is and isn't on the screen.

    I'm attaching the Map.java file that implements this for Android, and a text file explaining the steps to use this class to add a Google map to a Gideros app. The map class is fully functional. Next we need the plugin to provide access to the functions in this class from Lua.

    Ar2rsawseen, does this give you what you need to create the plugin for Android? If so I'll get started on the same native implementation for iOS.

    The following is the interface as I've implemented it in Java for Android:

    Map:new(): Constructor

    Map:show(): Display the map

    Map:hide(): Hide the map

    Map:setDimensions(int width, int height): Set size of map in pixels

    Map:setPosition(int x, int y): Set position of map on screen in pixels from top left

    Map:setCenterCoordinates(double latitude, double longitude): Center the map around the specified coordinates

    Map:setZoom(float zoom): Set zoom level from 0 (very large area) to 19 (zoomed in close)

    Map:setType(int map_type): Switch between MAP_TYPE_NORMAL, MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID, MAP_TYPE_TERRAIN

    Map:setMyLocationEnabled(boolean enabled): Turn on/off the “My location” button

    Map:mapClicked(): Return true if the map was clicked since last call

    Map:getMapClickLatitude(): Return latitude of last click on the map

    Map:getMapClickLongitude(): Return longitude of last click on the map

    Map:hasMoved(): Return true if map was moved since last call

    Map:getCenterLatitude(): Returns latitude of center of area shown

    Map:getCenterLongitude(): Returns longitude of center of area shown

    Map:clear(): Remove all markers

    Map:addMarker(double latitude, double longitude, String title): Adds a marker, and returns an index that can be used to access it

    Map:setMarkerTitle(int marker_idx, String title): Sets the title of the specified marker

    Map:setMarkerHue(int marker_idx, float hue): Sets the color of the specified marker in degrees around a color wheel, from red at 0 through the colors and back to red at 360. Defined for convenience: MAP_MARKER_RED, MAP_MARKER_ORANGLE, MAP_MARKER_YELLOW, MAP_MARKER_GREEN, MAP_MARKER_BLUE, MAP_MARKER_PURPLE

    Map:setMarkerAlpha(int marker_idx, float alpha): Set the alpha (transparency) of the specified marker

    Map:setMarkerCoordinates(int marker_idx, double latitude, double longitude): Moves the specified marker to the given coordinates

    Map:String getMarkerTitle(int marker_idx): Sets the title of the specified marker

    Map:getMarkerLatitude(int marker_idx): Returns the latitude of the specified marker

    Map:getMarkerLongitude(int marker_idx): Returns the longitude of the specified marker

    Map:getClickedMarkerIndex(): Return the index of the last marker clicked, if any since last call
    zip
    zip
    JavaMapClass.zip
    6K

    Likes: antix, simwhi, pie

    +1 -1 (+3 / -0 )Share on Facebook
  • antixantix Member
    @PaulH, WOW! amazing stuff. I hope this will be enough to get it added in the near future :)
Sign In or Register to comment.