티스토리 뷰
앞서서 포스트한 Swift 에서의 설계는 흡사하다.
차이점은 플랫폼이 Android 라는것, 사용된 언어가 C#이라는 것, Alamofire 대신 OkHttp3를 사용했다는 것 뿐이다.
자세한 설명은 해당 포스트를 참고하면 이해에 도움이 될 것이다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using Android.Webkit; using LayoutParams = Android.Views.ViewGroup.LayoutParams; namespace RhythmGayM { [Activity(Label = "CFDDoSWebViewActivity", Theme = "@android:style/Theme.DeviceDefault", Icon = "@mipmap/icon", ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait)] public class CFDDoSWebViewActivity : Activity { private readonly Lazy<WebView> webViewMain; public CFDDoSWebViewActivity() { this.webViewMain = new Lazy<WebView>(() => new WebView(this)); } protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); this.webViewMain.Value.LayoutParameters = new LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent); this.SetContentView(this.webViewMain.Value); if ((int)Build.VERSION.SdkInt < 21) CookieManager.Instance.RemoveAllCookie(); else CookieManager.Instance.RemoveAllCookies(null); var openURL = this.Intent.GetStringExtra("openURL"); var userAgent = this.Intent.GetStringExtra("userAgent"); var client = new CFWebViewClient(); client.completion = delegate (string cookies) { Intent intent = new Intent("kr.lonelie.CFDDoSWebViewActivity"); intent.PutExtra("cookies", cookies); this.SendBroadcast(intent); this.Finish(); }; this.webViewMain.Value.Settings.UserAgentString = userAgent; this.webViewMain.Value.SetWebViewClient(client); this.webViewMain.Value.Settings.JavaScriptEnabled = true; this.webViewMain.Value.LoadUrl(openURL); this.Title = "Cloudflare"; } public static void show(string url, string userAgent, Action<string> completion) { var cfDDoSIntent = new Android.Content.Intent(Application.Context, typeof(CFDDoSWebViewActivity)); cfDDoSIntent.PutExtra("openURL", url); cfDDoSIntent.PutExtra("userAgent", userAgent); IntentFilter filter = new IntentFilter(); CFBroadcastReceiver receiver = new CFBroadcastReceiver(); receiver.completion = completion; filter.AddAction("kr.lonelie.CFDDoSWebViewActivity"); Application.Context.RegisterReceiver(receiver, filter); cfDDoSIntent.SetFlags(ActivityFlags.NewTask); Application.Context.StartActivity(cfDDoSIntent); } } public class CFBroadcastReceiver : BroadcastReceiver { public Action<string> completion; public override void OnReceive(Context context, Intent intent) { //throw new NotImplementedException(); if (intent.Action.Equals("kr.lonelie.CFDDoSWebViewActivity")) { string cookies = intent.GetStringExtra("cookies"); Console.WriteLine("CF-WAF COOKIE: {0}", cookies); if (this.completion != null) this.completion(cookies); } } } public class CFWebViewClient : WebViewClient { public Action<string> completion; public override void OnPageStarted(WebView view, string url, Android.Graphics.Bitmap favicon) { string cookies = CookieManager.Instance.GetCookie(url) ?? ""; bool isFindCookieCFDUID = cookies.Contains("__cfduid="); bool isFindCookieCFClearance = cookies.Contains("cf_clearance="); if (isFindCookieCFDUID && isFindCookieCFClearance) { view.StopLoading(); if (this.completion != null) completion(cookies); } } } }
이전 Swift의 구현과 차이점이라면 Activity를 시작할 때 값을 넘겨주기 위해 Intent의 putExtra를 사용하는데, 여기에 람다대수(또는 블럭코드, 델리게이트) 를 전달할 수 없다.
때문에 작업 완료 시점을 콜백 받기 위해 브로드캐스트리시버를 사용했다. 그 외의 동작 방식은 Swift와 대동소이하다.
string contentType = response.Headers().Values("content-type")[0]; if (contentType.Contains("text/html")) { // Rejected request from DDoS protection in CF-WAF. Console.WriteLine("DETECT PROTECT DDOS IN CF-WAF."); CFDDoSWebViewActivity.show(urlString, CoreClient.userAgent, (cookies) => { CoreClient.cfCookies = cookies; CoreClient.request(method, resourcePath, parameters, closure); }); } else { // OK. /* blah blah */ }
이 부분은 Swift의 구현과 상당히 유사해 보이는 것을 알 수 있을 것이다.
단 Alamofire는 Iterable<HTTPCookie> 이고 HTTPCookie는 이름, 값, URL, 유효시간 등을 모두 가지는 객체인 반면,
OkHttp3 에서는 StringLiteral 이다. 요청시 Header라는 Dictionary<string, string>에 "Cookie" 라는 이름으로 추가한 후 요청하면 된다.
여기까지 진행되면 API 통신은 문제없이 동작할 것이다.
OkHttpClient client = new OkHttpClient.Builder() .ConnectTimeout(10, TimeUnit.Seconds) .ReadTimeout(0, TimeUnit.Seconds) .WriteTimeout(0, TimeUnit.Seconds) .Build(); Request request = new Request.Builder() .Url(this.chatServerURL) .AddHeader("token", UserInfo.token) .AddHeader("secret", UserInfo.tokenSecret) .AddHeader("Cookie", CoreClient.cfCookies) .AddHeader("User-Agent", CoreClient.userAgent) .Build();
다음으로 OkHttp3.WS 를 사용하여 연결 요청을 할 때, 리퀘스트 빌더에 "Cookie" 와 "User-Agent" 헤더를 추가하면 웹소켓 연결도 문제없이 된다.
이 부분은 Swift의 Starscream에서 사용한 방법과 매우 유사했다.
Console.WriteLine("Downloading: {0}", url); if (!isCached) { try { using (var webClient = new WebClient()) { webClient.Headers.Add("User-Agent", CoreClient.userAgent); webClient.Headers.Add("Cookie", CoreClient.cfCookies); imageBytes = webClient.DownloadData(url); Console.WriteLine("Download complete: {0} ({1} bytes).", url, imageBytes.Length); if (imageBytes != null) caches[url] = imageBytes; } } catch (Exception error) { Console.WriteLine("Download image failed: {0} -> {1}", url, error); } } else Console.WriteLine("Read cache: {0} ({1} bytes).", url, imageBytes.Length);
개인적으로 구현하여 사용중인 이미지 리소스 다운로드 코드이다.
WebClient 를 인스턴스하여 사용하고 있고, VS 솔루션 설정에서 AndroidClientHandler와 Native TLS 1.2+ 구현을 사용하도록 설정했다.
Swift 에서는 URLRequest를 사용하여 HTTPCookieStorage.shared에 들어있는 쿠키를 자동으로 핸들링 했었지만, WebClient는 위 코드처럼 추가해 주었다.
이 부분에 있어서도 세부적인 부분이 조금씩 다를 뿐 맥락은 Swift의 동작과 흡사하다고 보면 된다.
여기까지 진행하여 실제 스토어에서 판매중인 내 프로젝트의 iOS앱과 Android앱에서 동일한 동작을 구현하였다.
'Study > Development' 카테고리의 다른 글
Cloudflare 사용시 WAF 걸린 API 처리 #1 - Swift & Alamofire (0) | 2018.04.28 |
---|---|
코다2가 매우 편하구나! (0) | 2012.06.05 |
- TAG
- Android, CF, CloudFlare, csharp, DDoS, restapi, visualstudio, WAF, Xamarin
- Total
- 104,101
- Today
- 0
- Yesterday
- 7
- airserver
- 디아블로 3
- Raspberry Pi
- Time Capsule
- restapi
- CF
- OS X Server
- Crack
- OS X 10.8
- Revers DNS
- OS X
- 서코
- Xcode
- DDoS
- Mavericks
- 라즈베리 파이
- 서울 코믹월드
- CloudFlare
- Diablo III
- Mountain Lion
- 마비노기
- server
- macOS Server
- 에어서버
- 산사자
- 리플렉션
- rDNS
- WAF
- reflection