Java Question B4A 6 beta - How to add aar in Eclipse-project

Discussion in 'Libraries developers questions' started by DonManfred, Jun 9, 2016.

  1. DonManfred

    DonManfred Expert Licensed User

    How do i add support for aar files in Eclipse when i write a wrapper for a library?

    Otherwise; if it is better to use android studio: How do i need to start a new project to wrap a third party library with android studio but i want to compile the wrapper with SLC?

    Any hints on this?
     
  2. Erel

    Erel Administrator Staff Member Licensed User

    Assuming that you have an aar file:

    1. Open the aar file with 7zip and extract classes.jar.
    2. Put this jar in the libs folder.
    3. In the @DependsOn annotation you should write: @DependsOn(values={"NameOfTheAAR.aar"})

    Your library will be made of 3 files:
    <your library>.xml
    <your library>.jar
    <aar file>.aar

    The advantage of aar libraries is that assets and resources are added automatically.
     
  3. DonManfred

    DonManfred Expert Licensed User

    i understand... the added classes.jar will help with the imports as it is the jar i usually would add...

    Thank you. I´m sure i´ll have a first test soon :)
     
  4. corwin42

    corwin42 Expert Licensed User

    Will it be the same for libraries which use Google Play services and the support library?
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    Start with my answer here: https://www.b4x.com/android/forum/t...to-google-play-services-fused-location.67748/

    Example of library that depends on Firebase:
    Code:
    package anywheresoftware.b4a.objects;

    import java.io.Serializable;
    import java.util.Map.Entry;

    import android.os.Bundle;
    import anywheresoftware.b4a.AbsObjectWrapper;
    import anywheresoftware.b4a.BA;
    import anywheresoftware.b4a.BA.DependsOn;
    import anywheresoftware.b4a.BA.ShortName;
    import anywheresoftware.b4a.BA.Version;
    import anywheresoftware.b4a.objects.collections.Map;

    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GoogleApiAvailability;
    import com.google.firebase.analytics.FirebaseAnalytics;

    @ShortName(
    "FirebaseAnalytics")
    @Version(
    1.0f)
    @DependsOn(values={
    "com.google.firebase:firebase-crash""com.google.firebase:firebase-analytics"})
    public class FirebaseAnalyticsWrapper extends AbsObjectWrapper<FirebaseAnalytics>{
       /**
        * Initializes the object. FirebaseAnalytics should be a process global variable in the Starter service. It should be initialized in Service_Create sub.
        */
       public void Initialize() {
         setObject(FirebaseAnalytics.getInstance(BA.applicationContext));
       }
       /**
        * Sends an event to the analytics service.
        *EventName - Event name.
        *Parameters - Map of parameters. Pass Null if not needed.
        */
       public void SendEvent(String EventName, Map Parameters) {
         Bundle bundle = new Bundle();
         if (Parameters != null && Parameters.IsInitialized()) {
           for (Entry<Object, Object> e : Parameters.getObject().entrySet()) {
             bundle.putSerializable(String.valueOf(e.getKey()), (Serializable)e.getValue());
           }
         }
         getObject().logEvent(EventName, bundle);
       }
       /**
        * Tests whether Google Play Services are avaialable on the device.
        */
       public boolean getIsGooglePlayServicesAvailable() {
         return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(BA.applicationContext) == ConnectionResult.SUCCESS;
       }
    }
    It is similar to how you need to reference Google Play services. Secondary dependencies will be added automatically.
    List of services: https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project
    Note that the version should not be included.

    During compilation you need to reference a jar. You can use B4A to create this jar.

    Create a new project and add the dependencies with #AdditionalJar.
    For example:
    Code:
    #AdditionalJar: com.google.android.gms:play-services-drive
    You will now find the jar with all the relevant classes under Objects\bin\extra. You can take opt.jar or stan.jar. They are the same.
     
  6. corwin42

    corwin42 Expert Licensed User

    Can the version be included?
    This would be interesting for the support library. In the past Google released some versions of the support library which were buggy like hell. Would be nice if we could go back to an older version.

    That's a nice feature.

    I think I understand now and will try to update a first simple library to the new system (Perhaps AHViewPager because it only uses the v4 support library which should be simple).

    One question: If I have a library that uses the old .jar file in @DependsOn and another library which uses the same library from the maven repository in @DependsOn I guess only the maven library will be used?

    The biggest advantage of the new method seems to be that you won't have to add all these resources with #AdditionalRes attribute. Makes things much easier for the developers.
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    The biggest advantage is that you can use the new libraries such as Firebase and Google Play Services. They are no longer distributed as a single package.

    The version will not be added for now.
    If there is at least one reference to a maven library then references to google-play-services.jar and android-support-v4.jar will be ignored.
     
    corwin42 likes this.
  8. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    Erel, do you have a "complete" simple project using .AAR file to create a B4A library? A simple one.

    Can compile with SCL? Or needed Eclipse project?

    Thank You

    Alberto Iglesias
     
  9. DonManfred

    DonManfred Expert Licensed User

    yes

    This is the code for my Remoteconfig wrap

    Code:
    package de.donmanfred;

    import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
    import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo;
    import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
    import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue;
    import com.google.android.gms.tasks.OnCompleteListener;
    import com.google.android.gms.tasks.Task;

    import anywheresoftware.b4a.AbsObjectWrapper;
    import anywheresoftware.b4a.BA;
    import anywheresoftware.b4a.BA.Author;
    import anywheresoftware.b4a.BA.DependsOn;
    import anywheresoftware.b4a.BA.Events;
    import anywheresoftware.b4a.BA.Hide;
    import anywheresoftware.b4a.BA.ShortName;
    import anywheresoftware.b4a.BA.Version;
    import anywheresoftware.b4a.objects.collections.Map;

    @Version(
    1.01f)
    @ShortName(
    "RemoteConfig")
    @Author(value = 
    "DonManfred (wrapper)")
    //@Permissions(values={
    "android.permission.INTERNET""android.permission.ACCESS_NETWORK_STATE"})
    @Events(values={"onFetchComplete(success As Boolean)"})
    @DependsOn(values={"com.google.firebase:firebase-config","com.google.firebase:firebase-core"})
    //@DesignerProperties(values = {
    //        @Property(key="Checked", displayName="Checked", defaultValue="False", fieldType="Boolean")
    //    })
    public class FirebaseRemoteConfigWrapper extends AbsObjectWrapper<FirebaseRemoteConfig> {
        private BA ba;
        private String eventName;

        public static final boolean DEFAULT_VALUE_FOR_BOOLEAN = false;
        public static final double DEFAULT_VALUE_FOR_DOUBLE = 0.0;
        public static final long DEFAULT_VALUE_FOR_LONG = 0;
        public static final String DEFAULT_VALUE_FOR_STRING = "";
        public static final int LAST_FETCH_STATUS_FAILURE = 1;
        public static final int LAST_FETCH_STATUS_NO_FETCH_YET = 0;
        public static final int LAST_FETCH_STATUS_SUCCESS = -1;
        public static final int LAST_FETCH_STATUS_THROTTLED = 2;
        public static final int VALUE_SOURCE_DEFAULT = 1;
        public static final int VALUE_SOURCE_REMOTE = 2;
        public static final int VALUE_SOURCE_STATIC = 0;
       
       
        public void Initialize(final BA ba, String EventName) {
            this.eventName = EventName.toLowerCase(BA.cul);
            this.ba = ba;

            FirebaseRemoteConfig mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
            final String eventName = EventName.toLowerCase(BA.cul);
            setObject(mFirebaseRemoteConfig);
            //getObject().fetch(cacheExpirationSeconds)
       
        }
        /**
         * Fetches parameter values for your app. Configuration values may be served
         * from the Default Config (local cache) or from the Remote Config Server,
         * depending on how much time has elapsed since parameter values were last
         * fetched from the Remote Config server. This method lets the caller
         * specify the cache expiration in seconds.
         * @return
         */
    //    public Task<Void> fetch (long cacheExpirationSeconds){
    //        return getObject().fetch(cacheExpirationSeconds);
    //    }

        /**
         * Fetches parameter values for your app. Parameter values may be from the
         * Default Config (local cache), or from the Remote Config Server,
         * depending on how much time has elapsed since parameter values were last
         * fetched from the Remote Config server. This method uses the default
         * cache expiration of 12 hours.
         * @return
         */
    //    public Task<Void> fetch(){
    //        return getObject().fetch();
    //    }

        public boolean activateFetched(){
            return getObject().activateFetched();
        }
        /**
         * Gets the current state of the
         * FirebaseRemoteConfig singleton object.
         *
         * returns A FirebaseRemoteConfigInfo wrapping the current state.
         */
        public FirebaseRemoteConfigInfo getInfo(){
            return getObject().getInfo();
        }

        /**
         * Sets defaults in the default namespace,
         * using an XML resource.
         * @param resourceId
         */
        @Hide()
        public void setDefaults (String resource){
             BA.Log("Calling SetDefaults... "+resource);
            int resourceId=BA.applicationContext.getResources().getIdentifier(resource, "values", BA.packageName);
             BA.Log("resourceID="+resourceId);
           
            //getObject().setDefaults(arg0);
            //getObject().setDefaults(arg0, namespace);
            //getObject().setDefaults(Object map);
            //java.util.Map javaMap = map.getObject();
        }
       
        public void fetch(int cacheExpiration){
            getObject().fetch(cacheExpiration)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
          @Override
          public void onComplete(Task<Void> task) {
              if (task.isSuccessful()) {
                  BA.Log("Fetch Succeeded");
                         if (ba.subExists(eventName + "_onfetchcomplete")) {
                          BA.Log("lib:Raising.. "+eventName + "_onfetchcomplete()");                               
                          //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                          ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_onfetchcomplete", true, new Object[] {task.isSuccessful()});
                      }else {
                          BA.Log("lib: NOTFOUND '"+eventName + "_onfetchcomplete");
                      }
                         // Once the config is successfully fetched it must be activated before newly fetched
                         // values are returned.
                //getObject().activateFetched(); 
              } else {
                  BA.LogError("Fetch failed");
                           if (ba.subExists(eventName + "_onfetchcomplete")) {
                            BA.Log("lib:Raising.. "+eventName + "_onfetchcomplete()");                               
                            //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                            ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_onfetchcomplete", true, new Object[] {task.isSuccessful()});
                        }else {
                            BA.Log("lib: NOTFOUND '"+eventName + "_onfetchcomplete");
                        }
              }
          }
      });
        }
       
       
        @SuppressWarnings("unchecked")
        public void Defaults(Map defaults){
            @SuppressWarnings("rawtypes")
            java.util.Map m = defaults.getObject();
            getObject().setDefaults(m);
        }
        public void setDefaults2(Map defaults, String namespace){
            @SuppressWarnings("rawtypes")
            java.util.Map m = defaults.getObject();
            getObject().setDefaults(m, namespace);
        }

    //    /**
    //     * Sets defaults in the given namespace,
    //     * using an XML resource
    //     * @param resourceId
    //     */
    //    @Hide()
    //    public void Defaults2(int resourceId, String namespace){
    //        getObject().setDefaults(resourceId, namespace);
    //    }

        /**
         * Changes the settings for the FirebaseRemoteConfig
         * object's operations, such as turning the developer mode on.
         */
        public void setConfigSettings (FirebaseRemoteConfigSettings settings){
            getObject().setConfigSettings(settings);
        }
        /**
         * Gets the FirebaseRemoteConfigValue
         * corresponding to the specified key.
         */
        public FirebaseRemoteConfigValue getValue(String key){
            return getObject().getValue(key);
        }
        public FirebaseRemoteConfigValue getValue2(String key,String namespace){
            return getObject().getValue(key,namespace);
        }

        /**
         * Gets the value corresponding to the specified
         * key as a byte array.
         *
         * Returns Value as a byte array if a value
         * corresponding to the look up key was present;
         * default (if set) or static default value otherwise.
         */
        public byte[] getByteArray(String key){
            return getObject().getByteArray(key);
        }
        /**
         * Gets the value corresponding to the specified
         * key, in the specified namespace, as a byte array.
         *
         * Returns Value as a byte array if a value
         * corresponding to the look up key was present;
         * default (if set) or static default value otherwise.
         */
        public byte[] getByteArray2(String key,String namespace){
            return getObject().getByteArray(key,namespace);
        }

        /**
         * Gets the value corresponding to
         * the specified key, as a string.
         * 
         * returns alue as a string if a value corresponding
         * to the look up key was present and could be converted
         * to a string; default (if set) or
         * static default value otherwise.
         */
        public String getString(String key){
            return getObject().getString(key);
        }
        /**
         * Gets value as a string corresponding
         * to the specified key in the specified namespace.
         * returns alue as a string if a value corresponding
         * to the look up key was present and could be converted
         * to a string; default (if set) or
         * static default value otherwise.
         */
        public String getString2(String key,String namespace){
            return getObject().getString(key,namespace);
        }
       
       
        /**
         * Gets the value corresponding to the specified
         * key, in the specified namespace, as a double.
         *
         * Returns Value as a double if a value corresponding
         * to the look up key was present and could be
         * converted to a double; default (if set) or
         * static default value otherwise.
         */
        public double getDouble(String key){
            return getObject().getDouble(key);
        }   
        /**
         * Gets the value corresponding to the specified
         * key as a double.
         *
         * Returns Value as a double if a value corresponding
         * to the look up key was present and could be
         * converted to a double; default (if set) or
         * static default value otherwise.
         */
        public double getDouble2(String key,String namespace){
            return getObject().getDouble(key,namespace);
        }
       
       
        /**
         * Gets the value corresponding to the specified key,
         * as a boolean.
         */
        public boolean getBoolean(String key){
            return getObject().getBoolean(key);
        }
        /**
         * Gets the value corresponding to the specified key,
         * as a boolean, in the specified namespace.
         */
        public boolean getBoolean2(String key,String namespace){
            return getObject().getBoolean(key,namespace);
        }
       
        /**
         * Gets the value corresponding to the
         * specified key, as a long.
         * 
         * returns Value as a long if a value corresponding
         * to the look up key was present and could be
         * converted to a long; default (if set) or
         * static default value otherwise. 
         */
        public long getLong(String key){
            return getObject().getLong(key);
        }
        /**
         * Gets the value corresponding to the specified
         * key, in the specified namespace, as a long.
         */
        public long getLong2(String key,String namespace){
            return getObject().getLong(key,namespace);
        }
           
    }

    and

    Code:
    package de.donmanfred;

    import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue;

    import android.content.Context;
    import android.widget.TextView;
    import anywheresoftware.b4a.AbsObjectWrapper;
    import anywheresoftware.b4a.BA;
    import anywheresoftware.b4a.BA.ShortName;

    @ShortName(
    "RemoteConfigValue")
    //@ActivityObject()
    //@Permissions(values={
    "android.permission.INTERNET""android.permission.ACCESS_NETWORK_STATE"})
    //@Events(values={"onSigned(sign As Object)"})
    //@DependsOn(values={"android-viewbadger"})
    //@DesignerProperties(values = {
    //        @Property(key="Checked", displayName="Checked", defaultValue="False", fieldType="Boolean")
    //    })
    public class FirebaseRemoteConfigValueWrapper extends AbsObjectWrapper<FirebaseRemoteConfigValue> {
        private BA ba;

        public void Initialize(final BA ba, FirebaseRemoteConfigValue cfg) {
            final FirebaseRemoteConfigValue _obj = cfg;
            setObject(_obj);
        }

        public boolean asBoolean (){
            return getObject().asBoolean();
        }
        public byte[] asByteArray(){
            return getObject().asByteArray();       
        }
        public double asDouble(){
            return getObject().asDouble();
        }
        public long asLong(){
            return getObject().asLong();
        }
        public String asString(){
            return getObject().asString();
        }
        /**
         * VALUE_SOURCE_REMOTE if the value was retrieved
         * from the server, VALUE_SOURCE_DEFAULT if the
         * value was set as a default, or VALUE_SOURCE_STATIC
         * if no value was found and a static default
         * value was returned instead.
         */
        public int getSource(){
            return getObject().getSource();
        }
    }
    Hope it helps
     
    MarcoRome, koaunglay and Erel like this.
  10. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    Manfred, in this library you using a jar not aar, am i right?
     
  11. DonManfred

    DonManfred Expert Licensed User

    inside eclipse i used the classes.jar from the aar to be able to reference and to use the imports.
    but b4a will use the google aars due to the depends-on directive.
    if you want to directly reference a aar you can use

    Code:
    @DependsOn(values={"someaarfilename.1.2.3.aar")
    but you still need to ectract trhe classes.jar from the aar and add it to eclipses build-paths.
    In this case you need to copy the aar to additional libs folder.
     
    Erel likes this.
  12. ktlua

    ktlua Member Licensed User

    I am sorry that I am to this. I have an arr file form PayPal-Android-SDK-master:payPalAndroidSDK-aar.
    Kindly help guide me how to include this to my program. Do I need to process the files before it can be used?
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    Do you want to create a Java library? Do you know Java?
     
  14. ktlua

    ktlua Member Licensed User

    Sorry. My knowledge on Java is very limited.
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    Writing libraries requires some Java knowledge. You can find the jar file inside the aar package.
     
    ktlua likes this.
  16. ktlua

    ktlua Member Licensed User

    Thank you.

    I find a class.jar under the PayPalAndroidSDK-2.15.1.aar.
    I will try to use it.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice