Learning How To Learn 無事修了!
以前の記事で書いた Coursera の講座、Learning How To Learn を無事修了しました!
あまりのうれしさに修了証を画面キャプチャしてしまいましたよ。えぇ、いつでも見れるのにねw
以下終えた感想です。
続きを読むWWDC 2017 Customized Loading in WKWebView まとめ
WKWebViewの新機能に関する話
動画はこちら
Customized Loading in WKWebView
WebContentsを表示するにはいくつかの方法がある
- WKWebView
- SFSafariController
SFSafariControllerを使えばボタン等をOS側で処理してくれて楽
- ただし画面の一部に組み込みたいときには使えない
- その場合は
WKWebView
WKWebViewのプロセスはAppと分離される
- セキュリティ上の理由など
- それによる制約も強かった
今回は開発者から要望の多かった機能を3つ実装した
- Manage Cookies
- Filter unwatned content
- Provide custom resources
Manage Cookies
- WKHttpCookieStore
- クッキーを個別に追加/削除できる
- すべてのクッキーにアクセス可能
- クッキーの変更を監視可能
//GET let cookieStore = webView.configuration.websiteDataStore.httpCookieStore; cookieStore.getAllCookies() {(cookies) in } //ADD let cookie = HTTPCookie(properties: [ HTTPCookiePropertyKey.domain: "canineschool.org", HTTPCookiePropertyKey.path: "/", HTTPCookiePropertyKey.secure: true, HTTPCookiePropertyKey.name: "LoginSessionID", HTTPCookiePropertyKey.value: "5bd9d8cabc46041579a311230539b8d1"]) cookieStore.setCookie(cookie!) { webView.load(loggedInURLRequest) } //remove cookieStore.delete(cookie!) { webView.load(loggedOutURLRequest) }
Filtering unwanted content
見せたくないコンテンツをブロックできる
WKContentRuleList
JSONで記述、コード中でロードしWebViewに適用させる
//json-file in Bundle [{ "trigger": { "url-filter": ".*" }, "action": { "type": "make-https" } }] //swift-code //compile let jsonString = loadJSONFromBundle() WKContentRuleListStore.default().compileContentRuleList( forIdentifier: "ContentBlockingRules", encodedContentRuleList: jsonString ) { (contentRuleList, error) in if let error = error { return } createWebViewWithContentRuleList(ruleList!) } //access rules WKContentRuleListStore.default() .lookUpContentRuleList( forIdentifier: "ContentBlockingRules") { (contentRuleList, error) in //取得した情報を使う部分 } //apply let configuration = WKWebViewConfiguration() configuration.userContentController.add(contentRuleList)
Provide custom resources
- リソース読み込みをアプリで処理できるようになる
- ただしカスタムURLスキームに限る?)
将来的にも問題ないようにカスタムスキームを設定するように
- Bad : local
- Good : [AppName]-local
WKURLSchemeHandler を使う
class MyCustomSchemeHandler : NSObject, WKURLSchemeHandler { func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {} func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {} } let configuration = WKWebViewConfiguration() configuration.setURLSchemeHandler(MyCustomSchemeHandler(), forURLScheme: “custom-scheme")
WKURLSchemeTask
に結果を渡す
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { //Bundleからデータを読み込み、対応するResponseクラスを作成し渡す let resourceData : Data = loadDataFromBundle() let response = URLResponse( url: urlSchemeTask.request.url, mimeType: "text/html", //mimeType必須 expectedContentLength : resourceData.count, textEncodingName : nil ) urlSchemeTask.didReceive(response) urlSchemeTask.didReceive(resourceData) urlSchemeTask.didFinish() }
Kotlin-AltJSの初心者向けTips&インプレ
AltJS-Kotlin
Android公式言語採用で一気にメジャーになったKotlinですが、実は JavaScriptに変換できます。いつからかは知りませんが、かなり当初からできたはず(1.0より前からあったはず)。
しかしマイナーすぎてあまり使っている人を見たことがありません。ネットの記事も少なめ。
軽くですが触った範囲でのTips&を記述していきます。
Tips
最初にコツ&ハマりポイントを。あまり出回ってないと思いますので
イベントハンドラ
DOMのクリックイベント等をWindowにイベントハンドラを追加したいことはよくあると思います。こんなやつです
<script> function onLinkClick(param) { } </script> <a href="javascript:onLinkClick('PARAMETER')">LINK</a>
で、このonLinkClick相当をKotlinにしたい。コイツが地味にkotlinだと面倒、というより最初やり方がわかりませんでした。結論からいうと asDynamic()
を使います
fun main(args: Array<String>) { window.asDynamic().onLinkClick = {param : String -> //do anything } }
しかもmain関数内。最初はグローバル関数として記述すると思ってました。
jsの感覚で window.onLinkClick =
と書くとビルド通らないので注意してください。
console.log
コイツも地味にはまりました。 print
ですね。
一番ハマったのが、 改行がくるまでログに出力されない ことです。
このため、 print
単体では出力されません。そのあとの println で一気に出力されます。
これ結構ハマったので注意してください。
もいっこ、Object詳細をログに出してくれません。以下のようなパラメータをjs/kotlinに渡してログ出力させると…?
<a href="javascript:onLinkClick({text: 'I love Kotlin!'})">LINK</a>
上がconsole.log、下がkotlinのprintlnです。見ての通り、オブジェクトの詳細がわかりません
なので kotlinでも console.log を使ったほうがいい です。printを使うメリットが分かりませんでした。記法が少し短い程度でしょうか? 基本はconsole.logがいいと思います。
js連携
jsのコードと連携する場合、external
で定義ファイルを記述します。Typescriptでいう、 .d.ts
ですね。
ためしに以下のようなjs用をKotlinで使おうとすると…?
//myMathをモジュール的に使ってるイメージ myMath = {} //モジュール内関数 myMath.sin = function(degree) { return Math.sin(degree * Math.PI / 180.0) } //クラス myMath.Point = function(x, y) { self = this; this.x = x; this.y = y; this.abs = function() { return Math.sqrt(self.x * self.x + self.y * self.y); } }
Kotlin用の定義ファイルはこうなります。
//モジュールはclassで包む。もっといい方法あるかも external class myMath { //myMath.sinはstatic関数相当なので、companion objectで記述 companion object { fun sin(degree: Double) : Double } //内部クラスはそのまま。ただしコンストラクタは constructor に限定される模様 class Point { constructor(x: Double, y: Double) fun abs() : Double } } //ためしに使う fun main() { println(myMath.sin(90.0)) //1 val p = myMath.Point(1.0, 2.0) println(p.abs()); //2.23... }
こんな感じ。正直自分も把握しきってないです(触り始めたばかりですし)
適当に書いたあと出力JSファイルをみて、それが意図した結果になってるか確認してることが多いです。.d.ts
があるならそれベースでコンバートするのが楽でしょう。
小数はDoubleで
個人的にですが、小数は全部Doubleで扱ったほうが楽でした。Floatだといちいち末尾に f
が必要でちょっと面倒。またKotlinはこの辺結構厳格なので、Double/Floatが入り乱れるとキャストが面倒です。
その上、jsにコンバートされたら全部number です。Java変換なら意味ありますがjs変換ではDouble/Floatを使い分けるメリットがありません。そんなわけで記法が楽な Doubleに統一がベスト と判断しました。
IntとLongについてもほぼ同等です…が、こっちは気分で分けています。
ユーザIDなど64bitなものは明示的にLongにして、それ以外はIntとしてます。 普段からLongは逆に面倒 なので。
またLongはID程度でしか使わないので加減算などをしないんですよね。よってLongだから扱いが面倒ということはないです(時刻はDoubleで扱う)
こちらもコンバートされた結果はIntだろうがLongだろうが一緒のはず。
ここは地味にKotlinToJSで使いづらい部分ですね。Typescriptと違って整数と小数を分けれるのはいいと思うのですが、それ以上は過剰機能という印象です。
一致しないオブジェクトを渡したとき
たとえば次のような定義ファイルを記述したとします。
external class User { var id : Long var name : String }
idとnameがあるユーザ、よくあるパターンですね。これに {name: "NAME"}
というオブジェクト、idが不足してるオブジェクトを渡した場合…?
//htmlが、href='javascript:onClick({name: "NAME"})' window.asDynamyc().onClick(user : User) { println(user.id) //undefined println(user.name) //NAME }
と、undefinedになります。当然といえば当然ですが。このへんは型に厳しいKotlinといえど注意する必要があるので気をつけましょう。
定義ファイルを全部をNullableとして定義するのも手ですが、コードがかなりめんどくさくなるのがネックです。 このへんはバランスをみて、になるかと思います。
インプレッション
まだ軽く触り始めたばかりですが、インプレッションを
Cons
- 型があるのはやはりいい。TypeScriptより強力!
- 言語仕様はTypeScriptより組みやすい気がする
- IntelliJが賢い。VSCodeより補完がきく印象
- IntelliJが一つのJSファイルとして出力してくれるのでwebpack等を記述する必要がない。楽。
- どうもmain関数がある部分をエントリーポイントとして出力する模様
Pros
- HTML/JSとの連携が難しい。ここはTypeScriptに軍配があがる
- 型定義ファイルがほとんどない。自作する覚悟が必要。
- 標準クラスの設計がJava基準で、JSの標準APIとは相性が悪い
- 規模が大きい場合フレームワークをどうするか。
- React/Angular/Vueのどれとも相性悪そう
- フルスクラッチでいく覚悟が必要かもしれない
個人的印象ですが、 Kotlin内で閉じれるならすごくいい。閉じれない(外部JSと連携必須)ならTypeScript ということろでしょうか。
もちろんKotlin用外部ライブラリも少ないです。Androidのものなんて当然使いまわせません。
それに加え規模が大きくなるとReactやAngularは使いたくなるでしょう…ここは鬼門ですね。 小規模なプロジェクト以外は導入が難しそうなのに、小規模なプロジェクトで厳しい型チェックをするメリットは薄いというジレンマ。主力SPA系フレームワークとの相性悪そうなのは痛い。かろうじてAngular?
ちょっと面白いので趣味開発はありですが、業務採用となるとかなりハードルたかそうです。
こんな記事を書いておいてなんですが、個人的にはKotlinToJSよりELMのほうが面白いと思いますw