LoginSignup
0
0

【Android/Java】OkHTTPでDigest認証

Posted at

やりたいこと

AndroidアプリからDigest認証で通信したい
OkHTTPを使用することとしたらSingletonで作らないと、メモリを食いまくるようなので、それを意識する

Step1.実装方法

app¥build.gradle

android {
       :()
}
dependencies {
       :()
    implementation 'com.squareup.okhttp3:okhttp:4.11.0'
    implementation 'io.github.rburgst:okhttp-digest:3.1.0'
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <uses-permission android:name="android.permission.INTERNET" />

OkHttpSingleton.java

Singleton用のクラス

public final class OkHttpSingleton {
    private static OkHttpClient mInstance = null;

    /***
     * インスタンス生成(起動時1回)
     * @param context
     */
    public static void createInstance(Context context) {
        if (null == mInstance) {
            OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
            // 接続タイムアウト時間
            okHttpBuilder.readTimeout(30, TimeUnit.SECONDS);
            okHttpBuilder.connectTimeout(60, TimeUnit.SECONDS);

            // ファイルキャッシュ設定
            long currentTimeMillis = System.currentTimeMillis();
            currentTimeMillis -= 3 * 60 * 60 * 1000;     // キャッシュ有効期限(3時間前のデータ削除)

            int MAX_CACHE_SIZE = 100 * 1024 * 1024;      // 100 MiB
            File cachedFile = new File(context.getCacheDir(), "responses");
            if (cachedFile.exists() && cachedFile.lastModified() < currentTimeMillis) {
                cachedFile.delete();
            }
            Cache cache = new Cache(cachedFile, MAX_CACHE_SIZE);
            okHttpBuilder.cache(cache);

            // Digest認証
            if (context.getResources().getBoolean(R.bool.http_auth)) {
                final String authUser = "your user name";
                final String authPass = "your password";
                final DigestAuthenticator authenticator = new DigestAuthenticator(new Credentials(authUser, authPass));
                final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();

                okHttpBuilder.addInterceptor(new AuthenticationCacheInterceptor(authCache));
                okHttpBuilder.authenticator(new CachingAuthenticatorDecorator(authenticator, authCache));
            }

            mInstance = okHttpBuilder.build();
        }
    }

    /***
     * インスタンス 取得
     * @return okHttpClientオブジェクト
     */
    public static OkHttpClient getInstance() {
        return mInstance;
    }
}

OkHttpClientWorker.java

各通信の親クラス定義をWorkerで作成

// WorkerManager)
// https://developer.android.com/topic/libraries/architecture/workmanager?hl=ja
// https://qiita.com/naoi/items/e08f081fe42ef3694046
public abstract class OkHttpClientWorker extends Worker {
    private final String TAG = this.getClass().getSimpleName();
    protected Context mContext;
    private String mBaseUrl;

    public OkHttpClientWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        mContext = context;
        mBaseUrl = "https://www.hogefuga.com";
    }

    /**
     * HTTP通信要求
     */
    protected abstract void requestHttp();

    /**
     * API Responseに応じた内部処理 実行
     */
    protected abstract void exeWork(JSONObject respJson);


    /***
     * GET通信 パラメータ 生成/取得
     * @param params 通知パラメータ
     * @return URI   例)http://xxxx.co.jp/hoge/fuga
     *                                   ~~~~~~~~~~
     */
    private String getQuery(JSONArray params) {
        StringBuilder retQuery = new StringBuilder();
        try {
            for (int cnt = 0; cnt < params.length(); cnt++) {
                Iterator<String> keys = params.getJSONObject(cnt).keys();
                while (keys.hasNext()) {
                    String key = keys.next();
                    String value = params.getJSONObject(cnt).getString(key);
                    retQuery.append("/").append(value);
                }
            }
        } catch (Exception e) {
            retQuery = new StringBuilder();
        }
        return retQuery.toString();
    }

    /***
     * POST通信 パラメータ 生成/取得
     * @param params 通知パラメータ
     * @return ResponseData
     */
    private RequestBody postQuery(JSONArray params) {
        RequestBody requestBody = null;
        try {
            MediaType MIMEType = MediaType.parse("application/json; charset=utf-8");
            // JSONArray → String化
            StringBuilder postData = new StringBuilder();
            for (int cnt = 0; cnt < params.length(); cnt++) {
                postData.append(params.get(cnt)).append(",");
            }
            if (1 < postData.length()) {
                // POSTデータがない場合は、削除しない
                postData.deleteCharAt(postData.length() - 1);   // 最後のカンマ削除
            }
            requestBody = RequestBody.Companion.create(postData.toString(), MIMEType);
        } catch (Exception e) {
        }
        return requestBody;
    }

    /**
     * GET通信
     *
     * @param url   リクエストURL
     * @param param リクエストパラメータ
     */
    protected void requestGet(String url, JSONArray param) {
        final String urlStr = mBaseUrl + url + getQuery(param);
        Request request = new Request.Builder()
                .url(urlStr)
//              .addHeader("User-Agent", "hoge")
                .get()
                .build();
        exeRequestHttp(request);
    }

    /**
     * POST通信
     *
     * @param url   リクエストURL
     * @param param リクエストパラメータ
     */
    protected void requestPost(String url, JSONArray param) {
        url = mBaseUrl + url;
        final RequestBody postData = postQuery(param);
        Request request = new Request.Builder()
//              .addHeader("User-Agent", "hoge")
                .url(url)
                .post(postData)
                .build();

        exeRequestHttp(request);
    }

    /***
     * HTTP通信 実行
     * @param request リスエストデータ
     */
    private void exeRequestHttp(Request request) {
        OkHttpClient client = OkHttpSingleton.getInstance();
        // 非同期通信
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // ResponseをJSON形式へ
                JSONObject respJson = new JSONObject();
                respJson.put("result", false);
                respJson.put("message", e.getMessage());

                exeWork(respJson);
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    // ResponseをJSON形式へ
                    final String resp = response.body().string();
                    JSONObject tmp = new JSONObject(resp);


                    JSONObject respJson = new JSONObject();
                    respJson.put("result", true);
                    respJson.put("data", tmp.getString("data"));

                    exeWork(respJson);
                } catch (IOException | NullPointerException e) {
                }
            }
        });
    }
}

SampleRequest.java

OkHttpClientWorkerを継承した各通信用のクラス

public class SampleRequest extends OkHttpClientWorker {
    private final String TAG = this.getClass().getSimpleName();
    private Integer mSearchId;

    /**
     * コンストラクタ
     */
    public SampleRequest(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    /**
     * HTTP要求
     */
    @Override
    protected void requestHttp() {
        try {
            JSONArray request = new JSONArray();
            JSONObject tmp = new JSONObject();
            tmp.put("searchId", mSearchId);
            request.put(tmp);

            String url = "/search/user";
            requestGet(url, request);
        } catch (Exception e) {
        }
    }

    /**
     * API Responseに応じた内部処理 実行
     *
     * @param respJson
     */
    @Override
    protected void exeWork(JSONObject respJson) {
        try {
            do {
                if (respJson.getBoolean("result")) {
                    if (respJson.isNull("data")) {
                        break;
                    }
                    JSONObject jsonObject = respJson.getJSONObject("data");

                    String value1 = jsonObject.getString("value1");
                    String value2 = jsonObject.getString("value2");
                }
            } while (false);
        } catch (Exception e) {
        }
    }


    /**
     * WorkerThread HTTP通信
     */
    @NonNull
    @Override
    public Result doWork() {
        mSearchId = getInputData().getString("searchId");
        requestHttp();  // HTTP通信
        return Result.success();
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // HTTP通信
        WorkManager manager = WorkManager.getInstance(this);
        Data inputData = new Data.Builder()
            .putString("searchId", 1)
            .build();

        WorkRequest SampleRequest =
            new OneTimeWorkRequest.Builder(SampleRequest.class)
                .setInputData(inputData)
                .build();
         manager.enqueue(SampleRequest);
    }
}

解説

  1. OkHttpSingleton.java: OkHTTPのSingletonクラスを作成。このままコピペで使えると思う
  2. OkHttpClientWorker.java: 各通信に対しての親クラス。abstractメソッドで実装の強制化している。exeRequestHttp()メソッド内のResponse制御は、各通信に合わせてカスタマイズすれば使えると思います
  3. SampleRequest.java: 上記クラスを継承した各通信に特化したクラス。通信する内容ごとに、このようなクラスを作成する。WorkManagerを継承しており、以下の順序で呼ばれる
    【呼び出し順】
    ・SampleRequest.java:doWork()
    ・SampleRequest.java:requestHttp()
    ・OkHttpClientWorker.java:requestGet()/requestPost()
    ・OkHttpClientWorker.java:exeRequestHttp()
        ↓
    ・SampleRequest.java:exeWork()
  4. MainActivity.java: 実際に上記をクラスを使った通信の実行

最後に

おじさんは、Digest認証でめちゃくちゃハマッたので何かの役に立てたら幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0