๊ฐ์์์๋ ์ ์ฌ์ฉํ๊ณ ์๋๋ฐ, dio ๊ฐ ๋ ์ธ๊ธฐ ์๊ณ ๋ณดํธ์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ๋ฐ๋ผ์ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๊ณ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ์ค์ผ๋ก ์ค์ ํ ๊ฒ์ ์ ๋ฆฌํ๋ค.
ํจํค์ง ๊ตฌ์ฑ ๊ด์ ์์ ๋ฐ๋ผ๋ณธ Network
ํ๋์ ์ฑ์์ ๊ฐ๊ธฐ ๋ค๋ฅธ ์๋ฒ์ ํต์ ํ ์ผ์ด ํํ๊ณ , ์ด ๋ ๊ฐ ์๋ฒ์์ ํต์ ์ ์ฑ
์์ง๋ ํด๋ผ์ด์ธํธ๋ ๊ตฌ๋ถ์ ํด๋๋ ๊ฒ์ด ์ฝ๋ ํ์ฅ์ฑ์ด๋ ์ ์ง๋ณด์ ์ธก๋ฉด์์ ์ ๋ฆฌํ๋ค.
๊ทธ๋ ์ง๋ง ํํธ์ผ๋ก๋ ๊ฐ๊ธฐ ๋ค๋ฅธ ์๋ฒ์ ํต์ ํ๋ค๊ณ ํด๋ ๊ณตํต์ ์ผ๋ก ๊ฐ์ ธ์ผํ ์ญํ ๋ฐ ํํ๊ฐ ์์ ์ ๋ฐ์ ์๋ค. ๊ทธ๋์ ์ด๋ฌํ ๋ถ๋ถ์ ๊ณ ๋ คํด์ base_http_client ์ ๋ถ๋ฆฌํด๋์๊ณ ๊ฐ ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฅผ ์์ํด์ ๊ตฌํํ๋๋ก ์ฒ๋ฆฌํ๋ค.
interceptor ๋ ์ฉ๋๋ณ๋ก ์ต๋ํ ๋ถ๋ฆฌํด์ ๋ฐ๋ก ๊ตฌํ์ ํ์ฌ ํ์ํ ํด๋ผ์ด์ธํธ๊ฐ ์์์ ๊ฐ์ ธ๊ฐ์ ์ฌ์ฉํ๋๋ก ์ฒ๋ฆฌํ๋ค.
Network ๊ตฌํ
import 'package:dio/dio.dart';
abstract class BaseHttpClient with DioMixin implements Dio {
final String clientBaseUrl;
final List<Interceptor> customInterceptors;
BaseOptions? customOptions;
BaseHttpClient({
required this.clientBaseUrl,
required this.customInterceptors,
this.customOptions,
}) {
if (customOptions != null) {
options = customOptions!;
}
options.baseUrl = clientBaseUrl;
// options.connectTimeout = Duration(seconds: 5);
// options.receiveTimeout = Duration(seconds: 3);
interceptors.add(LogInterceptor(requestBody: true, responseBody: true));
interceptors.addAll(customInterceptors);
}
}
import 'package:app_frame_sample/data/network/client/base_http_client.dart';
class TodoApiClient extends BaseHttpClient {
TodoApiClient({
required super.clientBaseUrl,
required super.customInterceptors,
super.customOptions,
});
}
import 'dart:io';
import 'package:app_frame_sample/application/application.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:package_info_plus/package_info_plus.dart';
class BaseHeaderInterceptor extends InterceptorsWrapper {
@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
await _setHeaderWithAccessToken(options.headers);
await _setHeaderWithPackageInfo(options.headers);
await _setHeaderWithDeviceInfo(options.headers);
super.onRequest(options, handler);
}
Future<void> _setHeaderWithAccessToken(Map<String, dynamic> headers) async {
headers[HttpHeaders.authorizationHeader] =
await AccessManager.getAccessToken();
}
Future<void> _setHeaderWithPackageInfo(Map<String, dynamic> headers) async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
headers['appName'] = packageInfo.appName;
headers['packageName'] = packageInfo.packageName;
headers['version'] = packageInfo.version;
headers['buildNumber'] = packageInfo.buildNumber;
}
Future<void> _setHeaderWithDeviceInfo(Map<String, dynamic> headers) async {
final DeviceInfoPlugin deviceInfo = Injector.deviceInfoPlugin;
if (Platform.isAndroid) {
final AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
headers['uuid'] = androidInfo.id;
headers['operatingSystem'] = 'Android';
headers['operatingSystemVersion'] = androidInfo.version.sdkInt.toString();
return;
}
if (Platform.isIOS) {
final IosDeviceInfo iOSInfo = await deviceInfo.iosInfo;
headers['uuid'] = iOSInfo.identifierForVendor;
headers['operatingSystem'] = 'iOS';
headers['operatingSystemVersion'] = iOSInfo.systemVersion;
}
}
}
์ฌ๊ธฐ์ device ์ ๋ณด์ package ์ ๋ณด๋ฅผ ์ฝ๋๋ฐ ์ฌ์ฉ๋ ํจํค์ง๋ค์ ์๋์ ๊ฐ๋ค.
import 'package:shared_preferences/shared_preferences.dart';
class AccessManager {
static const String accessTokenKey = 'accessToken';
static Future<void> saveAccessToken(String accessToken) async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString(accessTokenKey, accessToken);
}
static Future<String> getAccessToken() async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
final String? accessToken = preferences.getString(accessTokenKey);
if (accessToken == null) {
return '';
}
return accessToken;
}
}