question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can't use Dagger to inject instances of `PublicClientApplication` into activities or fragments

See original GitHub issue

Is your feature request related to a problem? Please describe. I apologize for being so late with this feedback. I was previously using v0.2.2 and was held back because of the time required to update to using the new async methods we are required to call if on the main thread. Plus v0.2.2 was working totally fine aside from some very rare crashes.

I also realize that the synchronous methods for worker threads which throw exceptions if called on main thread was one of my requests (#544). I stand by that suggestion though and appreciate you adding them 😄.

What I didn’t realize til I updated was that there are now no public constructors for the IPublicClientApplication classes and their factory methods must also be called off of the main thread.

So here’s where my frustration begins, I previously used Dagger to build instances of PublicClientApplication which concentrated the configuration into a single place, and the client instance could simply be injected into fragments where I needed it. With the latest versions, this crashes since the object graph is created by dagger on the main thread, or at least the provider in the graph is invoked on the main thread when activities or fragments are injected in onCreate.

Now I need to enter “callback hell” in fragments where I need an instance of IPublicClientApplication, I have to use a callback to get it. If I need to call acquireToken, I have to get the client instance async with a callback, then also get the token (again with a callback):

val params = AcquireTokenParameters.Builder()
  .withCallback(object : AuthenticationCallback {
    override fun onSuccess(authenticationResult: IAuthenticationResult) { }
    override fun onCancel() = Timber.w("Cancelled")
    override fun onError(exception: MsalException) = Timber.e(exception, "Failed to get token")
  })
  .build()

PublicClientApplication.createSingleAccountPublicClientApplication(
  applicationContext,
  R.raw.msal_config,
  object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
    override fun onCreated(application: ISingleAccountPublicClientApplication) {
      application.acquireToken(params)
    }

    override fun onError(exception: MsalException) {
      Timber.e(exception, "Failed to initialize PublicClientApplication")
    }
  }
)

The README suggests storing the IPublicClientApplication instance in a field on the class once retrieved, but this is prone to race conditions, especially in java where nullability might not be enforced.

Creating the client requires reading a JSON file to load the configuration, which if performed on the main thread would trigger strict mode violations, or cause jank so I understand why this is also asynchronous.

Describe the solution you’d like I’d like the configuration loading to be performed lazily when needed. Then I can create a client instance with dagger and inject it easily. In this scenario any errors encountered configuring the client instance would be thrown by the synchronous acquireToken() methods or to the onError() method of the AuthenticationCallback. This would flatten the callback pyramid and make the API generally easier to use. Dagger or some other method could be used to save the client instance as a singleton as well.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
v-pocommented, Jan 29, 2022

Greetings! I don’t mean to resurrect this old issue. However, I thought I’d share my solution that builds upon some of the suggestions from this discussion. My intention was to support the more “modern” ways of working on Android (Dagger/Hilt, AAC VMs, Kotlin coroutines). The sample can be found here: https://github.com/v-po/msal-sample

It’s still very much a work in progress and I would greatly appreciate any feedback on it.

@joshfriend @MariusVolkhart @4gus71n - apologies for the ping, but just in case you might be interested ☺️

0reactions
joshfriendcommented, Jun 26, 2020

@MariusVolkhart while that suggestion is certainly an improvement over the current method, I would really like the library to handle as much of the background thread stuff as possible. Having the client app class lazy configure itself, then passing configuration errors to the callback in AuthenticationCallback seems like an alright solution to me.

Lazy would still require me to use an asynctask or something.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dagger 2 Injecting Fragment into Activity - error - Stack Overflow
The simplest solution would be to not inject the Fragment and just create it like you usually would.
Read more >
Using Dagger in Android apps
When using activities, inject Dagger in the activity's onCreate() method before calling super.onCreate() to avoid issues with fragment ...
Read more >
Dagger & Android
Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is developed by the Java Core Libraries Team...
Read more >
That Missing Guide: How to use Dagger2 | by Gabor Varadi
Dagger is a dependency injection framework, which makes it easier to manage the ... In our example, we cannot avoid using BackgroundScheduler and ......
Read more >
Dependency Injection with Dagger 2 - CodePath Cliffnotes
Many Android apps rely on instantiating objects that often require other dependencies. For instance, a Twitter API client may be built using a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found