20 Replies Latest reply on May 4, 2015 2:02 PM by Jon Tara

    Can't build Android native extension - undefined base

    Jon Tara

      I've written a native extension and implemented for iOS. Now want to implement for Android.

       

      Right now, just trying to implement and test calcSumm(), but having no luck building.

       

      All I have changed from the generated code is to remove getPlatformString() and joinStrings() demo functions (keeping calcSumm()).

       

      I get:

       

      Compiling java sources: ["/Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/RhodesSRC_build.files"]

      PWD: /Users/jon/.rvm/gems/ruby-2.2.2@rhodes-5.0.30-sp3-57e9d466-watusi/gems/rhodes-5.0.30

      CMD: /Library/Java/Home/bin/javac -g -d /Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/Rhodes -source 1.6 -target 1.6 -nowarn -encoding latin1 -classpath /Users/jon/sdk/android/sdk/platforms/android-22/android.jar:/Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/Rhodes:/Users/jon/sdk/android/sdk/extras/android/support/v4/android-support-v4.jar @/Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/RhodesSRC_build.files

      Note: Some input files use or override a deprecated API.

      Note: Recompile with -Xlint:deprecation for details.

      Note: Some input files use unchecked or unsafe operations.

      Note: Recompile with -Xlint:unchecked for details.

       

       

      PWD: /Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/Rhodes
      CMD: /Library/Java/Home/bin/jar cf /Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/librhodes/Rhodes.jar .
      -$TIME$- message [ build:android:rhodes FINISH ] time is { 2015-04-26T20:56:42Z } milliseconds from start (7139)
      -$TIME$- message [ build:android:extensions_java START ] time is { 2015-04-26T20:56:42Z } milliseconds from start (7140)
      Compile extensions java code
      /Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/extensions/coreapi/coreapi.jar is uptodate: true
      Compiling java sources: ["/var/folders/qs/mry441454mq56w00y5f59c200000gn/T/BonjourBrowserSRC_build20150426-39991-foco3u"]
      PWD: /Users/jon/.rvm/gems/ruby-2.2.2@rhodes-5.0.30-sp3-57e9d466-watusi/gems/rhodes-5.0.30
      CMD: /Library/Java/Home/bin/javac -g -d /Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/BonjourBrowser -source 1.6 -target 1.6 -nowarn -encoding latin1 -classpath /Users/jon/sdk/android/sdk/platforms/android-22/android.jar:/Users/jon/sdk/android/sdk/extras/android/support/v4/android-support-v4.jar:/Users/jon/workspace/Sargent/build/android/singer/development/bin/tmp/Rhodes:/Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/extensions/coreapi/android-support-v4.jar:/Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/extensions/coreapi/coreapi.jar:/Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/librhodes/Rhodes.jar:/Users/jon/workspace/Sargent/build/android/singer/development/bin/target/android/release/extensions/coreapi/coreapi.jar @/var/folders/qs/mry441454mq56w00y5f59c200000gn/T/BonjourBrowserSRC_build20150426-39991-foco3u
      /Users/jon/workspace/Sargent/build/android/singer/development/extensions/BonjourBrowser/ext/platform/android/src/com/rho/bonjourbrowser/BonjourBrowser.java:10: cannot find symbol
      symbol  : constructor BonjourBrowserBase()
      location: class com.rho.bonjourbrowser.BonjourBrowserBase
        public BonjourBrowser(String id) {
                                         ^
      1 error
      
      
      rake aborted!
      Error compiling java code
      

       

      BonjourBrowser.java

       

      package com.rho.bonjourbrowser;
      
      
      import java.util.Map;
      
      
      import com.rhomobile.rhodes.api.IMethodResult;
      import com.rhomobile.rhodes.api.MethodResult;
      
      
      public class BonjourBrowser extends BonjourBrowserBase implements IBonjourBrowser {
      
      
          public BonjourBrowser(String id) {
              super(id);
          }
      
      
          @Override
          public void calcSumm(int a, int b, IMethodResult result) {
                result.set(a+b);
          }
      
      
      }
      
      
      
      

       

      ext/platform/android/ext_java.files

      ext/platform/android/generated/src/com/rho/bonjourbrowser/BonjourBrowserBase.java
      ext/platform/android/generated/src/com/rho/bonjourbrowser/BonjourBrowserFactorySingleton.java
      ext/platform/android/generated/src/com/rho/bonjourbrowser/BonjourBrowserSingletonBase.java
      ext/platform/android/generated/src/com/rho/bonjourbrowser/IBonjourBrowser.java
      ext/platform/android/generated/src/com/rho/bonjourbrowser/IBonjourBrowserFactory.java
      ext/platform/android/generated/src/com/rho/bonjourbrowser/IBonjourBrowserSingleton.java
      ext/platform/android/src/com/rho/bonjourbrowser/BonjourBrowser.java
      ext/platform/android/src/com/rho/bonjourbrowser/BonjourBrowserFactory.java
      ext/platform/android/src/com/rho/bonjourbrowser/BonjourBrowserSingleton.java
      

       

      I'm afraid I know absolutely nothing about Android development. But I'd have expected the extension to build with the default code.

       

      I guess I am supposed to remove/comment super(id), but that doesn't make a difference.

       

      What am I missing?

        • Re: Can't build Android native extension - undefined base
          Jon Tara

          I generated a new app, and then generated a new extension, with same name as mine (was concerned might be issues with upper/lower case extension name, so used same name.

           

          Baffled because it builds just fine. I can't find any difference between the newly-generated API and mine, save for my iOS implementation, and the couple of generated demo methods that I removed.

           

          The file lists are identical.

           

          ext.yml is identical.

           

          Can't seem to find what is different. I guess I will have to move my extension out of the project to a safe place and start over (generate a new extension), then move my XML and my iOS code back in.

           

          Anybody else encounter this?

           

          Also, not sure now why it is that I should remove super(id). I didn't my my test app, and calcSumm() works. Not sure what that is supposed to accomplish, and the documentation doesn't give any reason.

            • Re: Re: Can't build Android native extension - undefined base
              Jon Tara

              I made some progress. At least it will build now. I figured-out from working with the small default project that I need to override every one of my methods, even if (initially) not implementing. That's not needed in an iOS extension.

               

              Not sure why I got the error message that I did initially, because on the default project, I did get a different error message...

               

              However, I have run-time problems:

               

              From my Settings controller (simple test), My expectation at this point is that I will get no callbacks from my calls to .search() since it is just a stub implementation on Android at this point. But I would have expected to be able to get properties. (Note the {{logInfo}} stuff gets substitute with calls to Rho::Log during build.)

               

                def bonjour_browser_search
                  # Note: default service type is '_http._tcp_.', default domain is '.local'
                  # All HTTP servers
                  Rho::BonjourBrowser.search({}, lambda do |callback_data|
                    {{#logInfo}} "got callback from Rho::BonjourBrowser.search callback_data = #{callback_data.inspect}" {{/logInfo}}
                    end # lambda
                  )
                  # Get two browsers going at once as a test
                  meta_browser = Rho::BonjourBrowser.new
                    meta_browser.search({serviceType: Rho::BonjourBrowser::SERVICE_TYPE_META_QUERY}, lambda do |callback_data|
                      {{#logInfo}} "got callback from (meta_browser) Rho::BonjourBrowser.search callback_data = #{callback_data.inspect}" {{/logInfo}}
                    end # lambda
                  )
                  {{#logInfo}}
                    [
                      "Rho::BonjourBrowser.serviceType = #{Rho::BonjourBrowser.serviceType.inspect}",
                      "Rho::BonjourBrowser.domain = #{Rho::BonjourBrowser.domain.inspect}",
                      "Rho::BonjourBrowser.getProperty('serviceType') = #{Rho::BonjourBrowser.getProperty('serviceType').inspect}",
                      "Rho::BonjourBrowser.getProperty('domain') = #{Rho::BonjourBrowser.getProperty('domain').inspect}",
                      "Rho::BonjourBrowser.getAllProperties = #{Rho::BonjourBrowser.getAllProperties.inspect}",
                      "Rho::BonjourBrowser.getProperties(['serviceType', 'domain']) = #{Rho::BonjourBrowser.getProperties(['serviceType', 'domain']).inspect}"
                    ]
                  {{/logInfo}}
                  Rho::BonjourBrowser.getAllProperties( lambda do |p|
                    {{#logInfo}}
                      "lambda property getter test: #{p.inspect}"
                    {{/logInfo}}
                  end )
                end
              
              

               

              /APP    ( 1812): I 04/27/2015 17:58:27:633 00000714  RhoWebChromeClient| click href =  -- From line 14 of http://127.0.0.1:8080/public/js/silent_post.js?1430169952
              I/chromium( 1812): [INFO:CONSOLE(14)] "click href = ", source: http://127.0.0.1:8080/public/js/silent_post.js?1430169952 (14)
              I/APP    ( 1812): I 04/27/2015 17:58:27:634 00000742          HttpServer| Process URI: '/app/Settings/bonjour_browser_search'
              I/APP    ( 1812): I 04/27/2015 17:58:27:635 00000742                  APP| RHO serve: /app/Settings/bonjour_browser_search
              I/APP    ( 1812): E 04/27/2015 17:58:27:635 00000742  BonjourBrowserRUBY| Error setting callback ^^^
              I/APP    ( 1812): E 04/27/2015 17:58:27:635 00000742  BonjourBrowserRUBY| Error setting callback ^^^
              I/APP    ( 1812): I 04/27/2015 17:58:27:636 00000742  SettingsController| [bonjour_browser_search](52) Rho::BonjourBrowser.serviceType = nil
              I/APP    ( 1812): I 04/27/2015 17:58:27:636 00000742  SettingsController| Rho::BonjourBrowser.domain = nil
              I/APP    ( 1812): I 04/27/2015 17:58:27:637 00000742  SettingsController| Rho::BonjourBrowser.getProperty('serviceType') = nil
              I/APP    ( 1812): I 04/27/2015 17:58:27:637 00000742  SettingsController| Rho::BonjourBrowser.getProperty('domain') = nil
              I/APP    ( 1812): I 04/27/2015 17:58:27:637 00000742  SettingsController| Rho::BonjourBrowser.getAllProperties = {"id"=>"SCN1"}
              I/APP    ( 1812): I 04/27/2015 17:58:27:637 00000742  SettingsController| Rho::BonjourBrowser.getProperties(['serviceType', 'domain']) = nil
              I/APP    ( 1812): E 04/27/2015 17:58:27:637 00000742  BonjourBrowserRUBY| Error setting callback ^^^
              I/APP    ( 1812): I 04/27/2015 17:58:27:638 00000742          HttpServer| GC Start.
              I/APP    ( 1812): I 04/27/2015 17:58:27:640 00000742          HttpServer| GC End.
              
              

               

              My only guess here is that Lambda callbacks do not work for Android?

               

              No, that can't be right, because I use lambda callbacks in some network code, and it work on both iOS and Android.

               

              Any clue what "error setting callback" means?

                • Re: Can't build Android native extension - undefined base
                  Jon Tara

                  Managed to reproduce the original error. It came back when I commented-out super(this) in the constructor. Clearly, that's erroneous advice in the documentation. What is actually needed? It doesn't seem it's possible to follow the example given in the documentation and actually wind-up with something working.

                   

                  Rhomobile | Building a native extension

                  ----

                  Now open extensions/greeting/ext/platform/android/src/com/rho/greeting/GreetingSingleton.java. This class is declared to implement the IGreetingSingleton interface we just saw in the previous step but it will not compile in its present form. This is an implementation class, which means it was autogenerated the first time but it is now up to you to make the relevant changes to implement the API correctly.

                  In order to do that:

                  • remove the call to super(this) in the constructor
                  • remove all existing methods

                  ----

                  • Re: Can't build Android native extension - undefined base
                    Jon Tara

                    "Error setting callback" message is found in generated code in the Ruby wrapper. It's an erroneous message, as far as I can tell. It's not an error. It just means no callback was found. Well, when you have an API with optional callback, it just might be that no callback will be found...

                     

                    I think maybe it is working as it should. I don't get back any properties to my property queries, because my 'start' method takes a hash as the first parameter and is supposed to merge the hash contents into properties. I haven't done that yet (for Android).

                     

                    At least it builds, and I do get a lonely ID property for the default instance...

                • Re: Can't build Android native extension - undefined base
                  Vijay Kumar Duddu

                  Yes, we did cover that at AppForum 2014. Links to all the presentations are on the right-hand side of the page. There are two on "Using Native Extensions" including one with sample code.

                    • Re: Can't build Android native extension - undefined base
                      Jon Tara

                      Thanks for the link.

                       

                      Unfortunately, those two sessions were both about creating WM extensions. I'm trying to create an Android extension.

                       

                      It's humbling to be stumbling-around on a platform you are unfamiliar with. I can write iOS extensions till the cows come home! But I'm pretty lost on Android.

                       

                      It doesn't help that I've written a pretty fully-featured extension for iOS. The examples I've seen are all rather basic. I'm trying to create a "poster child" extension with all of the bells and whistles.That is, it has:

                       

                      - properties

                      - constants

                      - a method that accepts (hopefully, an optional...) properties hash that get merged with existing properties

                      - a method with an optional callback (the same as the one above)

                      - asynchronous callbacks

                      - factory, with a default instance

                       

                      What I am finding, I am afraid, is that not all the bells and whistles work on every platform.

                       

                      I've had to go poking-around through the Rhodes source code for example code, and then figure out which APIs follow best practices, and which ones kludge it up in one way or another. I only find bits and pieces in different APIs, since no one API seems to fully embrace the 4.x+ API principles. Many of the Rhodes APIs collapse the implementation and base code together, which, of course, is a sensible optimization for core APIs, but makes it difficult to relate that code to how one might do it in a generated extension.

                       

                      I seem to be having trouble here with an optional callback. I'm not really sure how to handle that. In my iOS extension, in order to have an optional callback as the last parameter, I had to make the first parameter (an properties hash) mandatory. I haven't yet worked-out the code to allow the first parameter to be omitted. No big deal, for now I pass {} if I don't want to set any properties.

                       

                      It works fine in iOS. But for Android, my implementation of the method that has the optional callback ("browse") isn't even being called. The C ruby adapter code is giving an error message as shown above:

                       

                      1. I/APP    ( 1812): E 04/27/2015 17:58:27:635 00000742  BonjourBrowserRUBY| Error setting callback ^^^ 

                      And then never calls my implementation code. What is strange is that I DID supply a callback! I think that in the case of Android that the generated code assumes that the optional callback will be in the first parameter. maybe android C adapter code does some checking that iOS C adapter code does not. I will try making it a mandatory callback.

                       

                      My other methods (calcSumm() example and stopBrowsing() ) are being called. Finger seems to point at optional callback.

                       

                      Any help appreciated. I'll be open-sourcing this once I complete the Android implementation. (I have no interest in WM, but if somebody else wants to implement a bonjour browser for WM,..) That gives the community two useful things:

                       

                      - A Bonjour Browser extension

                      - An example extension that exercises all of the features of Factory-based extensions

                       

                      I've been working on this for now inside an app I am working on. But if anyone is interested in helping, I think the easiest thing would be for me to make a minimal sample app with the extension built-in.