bugfix> java > 投稿

私はトークンベースのApi認証(Laravel Passport)の実用的なコード例を持っていますが、Dagger 2はありません。現在の RetrofitBuilder.java からコードを移動したいAppModuleに追加して、アプリでDagger 2のパワーを使用できるようにします。
今のところ、Dagger Dependencyなしで、 RetrofitBuilder.java に2つの静的メソッドがありますこれは、認証されたルートの呼び出しと認証されていないルートの呼び出しに使用できます。
1) createService(service)  //これは、認証ヘッダーなしで(アクセストークンなしで)API呼び出しを行います
2) createServiceWithAuth(service, tokenManager)  //これは、アクセストークンなどの承認ヘッダーでAPI呼び出しを行います


Dagger依存関係を使用して同じ機能を実現する方法。上記の2つのメソッドをビジネスロジッククラス( UserRepository.java など)に提供するにはどうすればよいですか必要に応じて、認証済みおよび未認証のサービス呼び出しを行うことができます。

RetrofitBuilder.java

public class RetrofitBuilder {
    private static final String BASE_URL = "https://api.com/";
    private final static OkHttpClient client = buildClient();
    private final static Retrofit retrofit = buildRetrofit(client);
    private static OkHttpClient buildClient(){
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        Request.Builder builder = request.newBuilder()
                                .addHeader("Accept", "application/json")
                                .addHeader("Connection", "close");
                        request = builder.build();
                        return chain.proceed(request);
                    }
                });
        if(BuildConfig.DEBUG){
            builder.addNetworkInterceptor(new StethoInterceptor());
        }
        return builder.build();
    }
    private static Retrofit buildRetrofit(OkHttpClient client){
        return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(MoshiConverterFactory.create())
                .build();
    }
    public static <T> T createService(Class<T> service){
        return retrofit.create(service);
    }
    public static <T> T createServiceWithAuth(Class<T> service, final TokenManager tokenManager){
        OkHttpClient newClient = client.newBuilder().addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Request.Builder builder = request.newBuilder();
                if(tokenManager.getToken().getAccessToken() != null){
                    builder.addHeader("Authorization", "Bearer " + tokenManager.getToken().getAccessToken());
                }
                request = builder.build();
                return chain.proceed(request);
            }
        }).authenticator(CustomAuthenticator.getInstance(tokenManager)).build();
        Retrofit newRetrofit = retrofit.newBuilder().client(newClient).build();
        return newRetrofit.create(service);
    }
    public static Retrofit getRetrofit() {
        return retrofit;
    }
}

CustomAuthenticator.java (アクセストークンの有効期限が切れるとトークンを更新します)

public class CustomAuthenticator implements Authenticator {
    private TokenManager tokenManager;
    private static CustomAuthenticator INSTANCE;
    private CustomAuthenticator(TokenManager tokenManager){
        this.tokenManager = tokenManager;
    }
    static synchronized CustomAuthenticator getInstance(TokenManager tokenManager){
        if(INSTANCE == null){
            INSTANCE = new CustomAuthenticator(tokenManager);
        }
        return INSTANCE;
    }

    @Nullable
    @Override
    public Request authenticate(Route route, Response response) throws IOException {
        if(responseCount(response) >= 3){
            return null;
        }
        AccessToken token = tokenManager.getToken();
        ApiService service = RetrofitBuilder.createService(ApiService.class);
        Call<AccessToken> call = service.refresh(token.getRefreshToken() + "a");
        retrofit2.Response<AccessToken> res = call.execute();
        if(res.isSuccessful()){
            AccessToken newToken = res.body();
            tokenManager.saveToken(newToken);
            return response.request().newBuilder().header("Authorization", "Bearer " + res.body().getAccessToken()).build();
        }else{
            return null;
        }
    }
    private int responseCount(Response response) {
        int result = 1;
        while ((response = response.priorResponse()) != null) {
            result++;
        }
        return result;
    }
}


AppModule.java

@Module(includes = ViewModelModule.class)
public class AppModule {
    // --- DATABASE INJECTION ---
    @Provides
    @Singleton
    MyDatabase provideDatabase(Application application) {
        return Room.databaseBuilder(application,
                MyDatabase.class, "MyDatabase.db")
                .build();
    }
    @Provides
    @Singleton
    UserDao provideUserDao(MyDatabase database) { return database.userDao(); }
    // --- REPOSITORY INJECTION ---
    @Provides
    Executor provideExecutor() {
        return Executors.newSingleThreadExecutor();
    }
    @Provides
    @Singleton
    UserRepository provideUserRepository(UserWebservice webservice, UserDao userDao, Executor executor) {
        return new UserRepository(webservice, userDao, executor);
    }
    // --- NETWORK INJECTION ---
    private static String BASE_URL = "https://api.com/";
    @Provides
    Gson provideGson() { return new GsonBuilder().create(); }
    @Provides
    Retrofit provideRetrofit(Gson gson) {
        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl(BASE_URL)
                .build();
        return retrofit;
    }
    @Provides
    @Singleton
    UserWebservice provideApiWebservice(Retrofit restAdapter) {
        return restAdapter.create(UserWebservice.class);
    }
}

回答 1 件
  • okHttpの作成と後付けをDaggerモジュールに移動して、必要なサービスコンストラクターに割り当てることができます。

    次のようなコードで:

    @Module
    public class ServiceModule {
        @Provides
        @Singleton
        OkHttp provideOkHttp(Authenticator authenticator) {
            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        Request.Builder builder = request.newBuilder()
                                .addHeader("Accept", "application/json")
                                .addHeader("Connection", "close");
                        request = builder.build();
                        return chain.proceed(request);
                    }
                });
            if (BuildConfig.DEBUG) {
                builder.addNetworkInterceptor(new StethoInterceptor());
            }
            // build this authenticator in the same way as all the other dependencies shown here
            builder.authenticator(authenticator);
            return builder.build();
        }
        @Provides
        @Singleton
        Retrofit provideRetrofit(OkHttp okHttp) {
            return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttp)
                .addConverterFactory(MoshiConverterFactory.create())
                .build();
        }
        @Provides
        @Singleton
        Service provideService(Retrofit retrofit) {
            return new ServiceImpl(retrofit);
        }
    }
    
    

    ただし、コードはテストされていません...

あなたの答え