ZupIT/beagle

Can I use Beagle library in a module and register more actions/widgets in project?

Closed this issue · 9 comments

Use case

Hi guys,
I've been working with Beagle for a long time and I've created many custom actions/widgets for Android to serve my project.
Now I'm trying to gather all these custom actions/widgets into a module (for reuse purpose in my other projects in future) and then import this module into my current project. However, I realize that if I have to create one more action/widget right in my current project (these actions/widgets should have access to resources, classes,... in my project), that action or widget will not be compiled so that it does not appear in registeredWidgets() in BeagleSetup().

For above issue, I would like to ask whether there is anyone who ever tried this and did it successfully?
Thank you guys and look forward to seeing your responses!

What I've done so far

  1. Create a module named ExtendedBeagleLib that implements Beagle Library -> Write config classes such as AppBeagleConfig, BeagleLoggerDefault, HttpClientDefault,... -> Create custom actions/widgets
    Module-scope gradle:
dependencies {
          ...
          api "br.com.zup.beagle:android:$beagle_version"
          kapt "br.com.zup.beagle:android-processor:$beagle_version"
          ...
}
  1. Import this module into my current project:
    Project-scope gradle:
dependencies {
          ...
          implementation project(':ExtendedBeagleLib')
          ...
}

Hi @hoangnv11 thanks for your question.

We're currently working on our annotation processor to allow registering components in a multi-module project. Until this is done, you can achieve this behavior by not using Beagle's annotation processor and creating the BeagleSetup class yourself.

Hi @hoangnv11 thanks for your question.

We're currently working on our annotation processor to allow registering components in a multi-module project. Until this is done, you can achieve this behavior by not using Beagle's annotation processor and creating the BeagleSetup class yourself.

Thanks for your reply!
Do you mean that in future we will be able to register more components in any module within a project, right? So could you reveal when this will be available?
And for now, while I've been waiting for that release, is there any feasible way I can do to achieve the result as I describe above?

Yep. It will be possible to register components in any dependency that uses Beagle's annotation processor.
We're planning to release it in version 1.9 by the end of July.

For now, the only possible way to achieve this behavior is implementing the BeagleSetup class yourself.

Hey @hoangnv11 I will provide one example for you today <3

my example was based on your lib called ExtendedBeagleLib:

First, you need to modify the gradle of your lib to expose the files generated for the module that will consume it, for example below:

android {
....
    sourceSets {
        main {
            java {
                srcDir "${buildDir.absolutePath}/generated/source/kaptKotlin/"
            }
        }
    }


}

Second, you need to put the beagle lib as API so you can access the beagle stuff or duplicate the dependency on the module that will consume the lib I prefer to change to API, example below:

dependencies {
    // Beagle
    api "br.com.zup.beagle:android:$beagle_version"
    kapt "br.com.zup.beagle:android-processor:$beagle_version"
}

with these changes and for you to create your app, in android project view mode you can see the generated classes by clicking on java(generated) like the photo below:
Screen Shot 2021-06-30 at 12 06 44

The class that contains everything from the beagle is called BeagleSetup let's copy all that code and create ours, with that I'll add it in the class constructor to receive the components I want to add to the beagle:

import br.com.zup.beagle.analytics.Analytics
import br.com.zup.beagle.android.action.Action
import br.com.zup.beagle.android.action.FormLocalActionHandler
import br.com.zup.beagle.android.components.form.core.ValidatorHandler
import br.com.zup.beagle.android.data.serializer.adapter.generic.TypeAdapterResolver
import br.com.zup.beagle.android.imagedownloader.BeagleImageDownloader
import br.com.zup.beagle.android.logger.BeagleLogger
import br.com.zup.beagle.android.navigation.BeagleControllerReference
import br.com.zup.beagle.android.navigation.DeepLinkHandler
import br.com.zup.beagle.android.networking.HttpClient
import br.com.zup.beagle.android.networking.HttpClientFactory
import br.com.zup.beagle.android.networking.urlbuilder.UrlBuilder
import br.com.zup.beagle.android.operation.Operation
import br.com.zup.beagle.android.setup.BeagleConfig
import br.com.zup.beagle.android.setup.BeagleSdk
import br.com.zup.beagle.android.setup.DesignSystem
import br.com.zup.beagle.android.store.StoreHandler
import br.com.zup.beagle.android.view.BeagleActivity
import br.com.zup.beagle.android.widget.WidgetView
import br.com.zup.beagle.newanalytics.AnalyticsProvider

public class MyBeagleSetup(val widgets: List<Class<WidgetView>>) : BeagleSdk {
    public override val formLocalActionHandler: FormLocalActionHandler? = null

    public override val deepLinkHandler: DeepLinkHandler =
        com.vt.extendedbeaglelib.config.AppDeepLinkHandler()

    public override val httpClient: HttpClient =
        com.vt.extendedbeaglelib.config.httpclient.HttpClientDefault()

    public override val httpClientFactory: HttpClientFactory? = null

    public override val designSystem: DesignSystem = com.vt.extendedbeaglelib.config.AppDesignSystem()

    public override val storeHandler: StoreHandler? = null

    public override val urlBuilder: UrlBuilder? = null

    public override val analytics: Analytics? = null

    public override val analyticsProvider: AnalyticsProvider? = null

    public override val logger: BeagleLogger =
        com.vt.extendedbeaglelib.config.cache.BeagleLoggerDefault()

    public override val controllerReference: BeagleControllerReference =
        ControllerReferenceGenerated()

    public override val imageDownloader: BeagleImageDownloader? = null

    public override val serverDrivenActivity: Class<BeagleActivity> =
        br.com.zup.beagle.android.view.ServerDrivenActivity::class.java as Class<BeagleActivity>

    public override val config: BeagleConfig = AppBeagleConfig()

    public override val typeAdapterResolver: TypeAdapterResolver = RegisteredCustomTypeAdapter

    public override val validatorHandler: ValidatorHandler = RegisteredCustomValidator

    public override fun registeredWidgets(): List<Class<WidgetView>> =
        merge(RegisteredWidgets.registeredWidgets(), widgets)

    public override fun registeredOperations(): Map<String, Operation> =
        RegisteredOperations.registeredOperations()

    public override fun registeredActions(): List<Class<Action>> =
        RegisteredActions.registeredActions()
}


fun <T> merge(first: List<T>, second: List<T>): List<T> {
    val list: MutableList<T> = ArrayList()
    list.addAll(first)
    list.addAll(second)
    return list
}

before our application we called the BeagleSetup().init() class now we will need to call the class that we created with the changes, example below:

class SampleApplication : Application() {

    override fun onCreate() {
        super.onCreate()

//        BeagleSetup().init(this)
        MyBeagleSetup(listOf(LabelTwo::class.java as Class<WidgetView>)).init(this)
    }

}

I opened this pr for your example lib just to show you a way to do this, you can increment it and add actions for example, I believe that with that you can already have an idea of how to do it.

just tweaking the @paulomeurerzup comment we are planning to release this in 1.10 which would be at the end of July, the next version 1.9 will be released this Friday but it won't be ready until then.

I will close this issue, but if you have any doubts about the example, feel free to open another issue.
and to follow up the issue about the annotation processor: #1436

@uziasferreirazup Thank you a million for your immense enthusiasm! It helps me a lot.
I've got your idea of registering more custom components and I'll try it tomorrow morning as soon as I arrive at work, I believe it will work properly and this is extremely a brilliant idea <3

@paulomeurerzup @uziasferreirazup I would like to thank both of you for your quick replies as well as useful information :D
I'll stay tuned for the upcoming releases. You are doing a great job! 🥇