- 投稿日:2020-07-04T20:49:40+09:00
Kobiton でスマートフォンのリモートテストを試してみた
概要
昨今のテレワーク推進の中、スマートフォン開発における課題となるのが実機による動作検証です。
多種多様なスマートフォン端末の準備・利用は、利用者それぞれがテレワークしていると難しくなります。今回は上記課題を解決しうるリモート実機動作検証サービス Kobiton について調査しました。
TL; DR
- Kobiton https://kobiton.com/ はリモート実機検証できるサービス
- ブラウザからリモートの実機を操作して手動・自動での動作検証が可能
- デスクトップアプリを利用すると、自分たちで用意した実機を使っての動作検証も可能
- 30日間無料トライアル
リモートの実機による動作検証
Kobiton がクラウド上に用意した実機を使って動作確認を行うことができます。
利用可能な端末
利用可能な実機の一覧は以下のURLから参照できます。
https://docs.kobiton.com/devices-list/
2020年7月4日時点で208種類のAndroid・iOS端末を利用できます。
ログイン後には以下のような画面から利用する端末を選ぶことができます。
動作検証セッション
セッション中
動作検証中のセッションは以下のような画面です(以下の画面はAndroidの場合です)。
スワイプ等の操作は少々ラグがありますが、ブラウザから操作できていることを考えると十分でしょう。右上の「Install Apps」ボタンから、自分で登録したアプリをインストールすることができます。
これで自分で開発したアプリの動作確認ができます。セッションログ
セッション終了後はログが残ります。
動作確認した動画も自動で残ります。
セッションの詳細では、どの時点でどんな操作をしたか閲覧することもできます。
自分たちで用意した実機による動作検証
Kobiton がクラウド上に準備した端末は種類も多く便利ですが、不便な点もあります。
他の人が使用中だと使えなかったり、パブリックなネットワークにしかアクセスできなかったりします。これらの問題点を解決するため、Kobiton のデスクトップアプリを介して自分たちで用意した実機を使用することができます。
上記の問題点を解決しつつ、端末の管理は Kobiton のクラウド上の端末と同様に行うことができます。デスクトップアプリの準備
詳細は公式のドキュメントを見ていただくとよいかと思います。
Kobiton のデスクトップアプリは Mac OS でのみ使うことができます。
Windows アプリはないようです。
iOS 端末にも対応するためでしょうか。その後、 Android と iOS の設定を行います。
Android であれば JDK および Android SDK のパスを指定します。
iOS であれば Xcode のパスおよび証明書・プロビジョニングプロファイルの設定を行います。端末の登録
端末を接続すると、 Kobiton のアプリケーションが端末にインストールされます。
基本的にはこれだけで問題ないです。私が設定したときは、 追加で端末のデバイスロックを解除しておく必要がありました。
AndroidおよびiOSのトラブルシューティングのドキュメントが整備されているので、設定がうまくいかないときはご確認ください。端末の利用
設定が終われば、あとは Kobiton が提供する端末と同じように自分のローカル端末で動作確認を行うことができます。
まとめ
今回は Kobiton による実機端末を利用した動作確認について簡単に紹介しました。
Kobiton が提供する端末に加えて、自分の端末を利用することができます。Kobiton ではさらにテストの自動実行や各種便利APIの利用ができるようです。
Free Trial もあるため、興味が湧きましたらぜひ試して記事を公開してください
- 投稿日:2020-07-04T17:05:27+09:00
[RxSwift]flatMap系とcombineLatestの違い
flatMap
系使い方
a.flatMap(b)
,a.flatMapFirst(b)
,a.flatMapLatest(b)
等特徴
a
のonNext
の処理に、b
のonNext
の全処理を掛け合わせていく。
a
へのある要素への掛け合わせる処理が終わらないうちに、a
へさらに次の要素が流れてきた場合、
flatMapFirst
は次の要素を無視する
flatMapLatest
は現在の要素をキャンセルし次の要素の処理を行う
flatMap
は次の要素も現在の要素も両方行う。
combineLatest
使い方
Observable.combineLatest(a, b) { $0 + $1 }
等特徴
a
とb
の最新の要素を掛け合わせる。
- 投稿日:2020-07-04T11:48:41+09:00
iOS / Web版Twitterの指定したページへのリンクをホーム画面に追加する
TL;DR
Web版Twitterをホーム画面に追加する
-> PWAになり追加時のURLが反映されない別のページを経由して開けば解決
-> dataスキームdata URI scheme
- dataスキーム
- 外部リソースと同じようにデータを読み込む方法
- アドレスバーに入力する
iOSの「ホーム画面に追加」は後からURLを書き換えられない
-> 追加時用のTwitterを開かないパターンが必要
-> 端末がネットに繋がっているかで条件分岐(他にも方法はあると思う)data:text/html, <script> if (navigator.onLine) location.href='開くURL' </script>実際の手順
- 上記のdataスキームの「開くURL」部分を変更
- オフラインの状態でブラウザのアドレスバーに入力
- ホーム画面に追加
問題点
ホーム画面に表示されるアイコンが真っ白なので複数追加すると分かりにくい
↓↓↓
ページに背景色を設定する
<style> html {background: 色} <style>アイコンの画像を設定する
<link rel="apple-touch-icon-precomposed" href="画像のURL">以上
- 投稿日:2020-07-04T11:10:44+09:00
【Swift】ScrollViewがカクつく時の対処法
下記ブログの転載です!
https://rc-code.info/ios/post-273/iOSにて、
UIScrollView
のカクつきを改善する必要があったので備忘録。
今回はUIScrollViewDelegate.scrollViewDidScroll
を利用している時の対処法を紹介します。
UIScrollViewがカクつく理由
まず UIScrollView に限らず描画がカクつく場合、その理由は
mainthread
を圧迫していることがほとんどです。
mainthread
については、こちらを参考にしていただければと思います。scrollViewDidScroll内の処理を見直す
さて、今回解決したいのは
UIScrollView
のカクつきですが、scrollViewDidScroll
というUIScrollView.Delegate
の処理が重たくなりすぎているというケースがよく見られます。後述する対策は
scrollViewDidScroll
だけでなく、他のUIScrollView.Delegate
の関数にも有効な場合があるので、参考にしてみてください。UIScrollView のカクつきを再現する負荷試験
下記は
extension
でscrollViewDidScroll
を定義したサンプルになります。extension ViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { var count: Int = 0 var array: [Int] = [] repeat { array.append(count) array.reverse() count += 1 } while(count < 200) } }上記のソースでは、スクロールされる度に 0〜199 までの数字を配列に格納してはリバースするという再帰処理を行なっています。
count を array に格納しリバース、countに+1 (array=[0]、count=1 になる)
count を array に格納しリバース、countに+1 (array=[1,0]、count=2 になる)
以下、199まで繰り返し、、、この処理が少しでもスクロールされる度に行われるので、なかなか重いタスクとなります。
scrollViewDidScroll
という関数は、スクロール
というUI操作に紐づいているので、この重たい処理はmainthread
にて処理されてしまいます。
つまり、scrollViewDidScroll
関数内に負荷がかかると画面更新に影響するということです。
実際にこの処理を加えてUIScrollViewをスクロールしていただくと、カクつくことが分かると思います。カクつきを解消する方法
class ViewController: UIViewController { //スクロール処理用Queue private let scrollSessionQueue = DispatchQueue(label: "ScrollSessionQueue") ...以下省略 } extension ViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // mainthread を圧迫しないように、別スレッドで処理 scrollSessionQueue.async { var count: Int = 0 var array: [Int] = [] repeat { array.append(count) array.reverse() count += 1 } while(count < 200) } } }上記のソースでは、
ViewController
にscrollLogSessionQueue
というQueueを新たに呼び出しています。そして
scrollViewDidScroll
内の処理をscrollSessionQueue.async
で囲むことで、処理をmainthread
から別threadに移譲しています。
すなわち、処理はmainthread
ではなく、UIに関連しない別のthread
にて処理されることになります。実際に動かしてみると、スクロールが滑らかになっていることが分かると思います。
DispatchQueue
の詳しい生成方法については こちら を参考にしていただければと思います。修正後の注意点
ただ、別threadにて処理を行う際には注意が必要です。
主に挙げられる注意点は①別threadにすれば100%画面更新に影響がなくなるわけではない
②別threadに移譲するので、実行タイミングがズレるという2点です。
①についてですが、
scrollLogSessionQueue.async
で別スレッドを使ってもCPUやGPUが圧迫されることは免れませんし、別スレッド内の処理によっては再度mainthread
への移譲が行われるという事もあり得ます。
なので100%影響がなくなるというわけではありません。
サンプルコードscrollLogSessionQueue.async
の中で行われている処理の負荷を上げていくと、この事が分かるかと思います。②について、指定したthreadに処理を移譲するので、当然ながら処理は画面と同期しません。
画面的にはスムーズにスクロールしたり、スクロールが既に完了していても、scrollLogSessionQueue.async
内の処理が同様に完了しているとは限らないので、注意が必要です。
検証Playground
検証環境
Mac: 10.14.4
XCode: 10.2
Swift: 5.0
参考ドキュメント
- 投稿日:2020-07-04T11:08:23+09:00
【Swift】WKWebViewでJavaScriptのコールバックを受けつける(WKUserContentControllerの使い方)
下記ブログの転載です!
https://rc-code.info/ios/post-194/iOSにて、
WKWebView
でJavaScriptのコールバックを受けつける必要があったので備忘録。
今回はWKUserContentController
を利用した方法を紹介します。
WKWebView の使い方
まずは
WKWebView
の基本的な使い方ですが、こちらを参考にしていただければと思います。
WKUserContentController の使い方
WKUserContentController
はJavaScript
からのコールバック受信や、スクリプトをWebビューに挿入する方法を提供します。
下記が導入のサンプルコードです。import UIKit import WebKit class ViewController: UIViewController { var webView: WKWebView! override func loadView() { // ① WKUserContentController の生成 let userContentController = WKUserContentController() // ② WKUserContentController にコールバックハンドラを登録 userContentController.add(self, name: "jsCallbackHandler") let webConfiguration = WKWebViewConfiguration() // ③ WKWebViewConfiguration に生成した WKUserContentController を登録する webConfiguration.userContentController = userContentController webView = WKWebView(frame: .zero, configuration: webConfiguration) view = webView } } // ④ WKScriptMessageHandler のデリゲートを記載 extension ViewController: WKScriptMessageHandler { // ⑤ JavaScript から呼び出されるコールバックハンドラ関数を記載 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { switch message.name { case "jsCallbackHandler": print("Javascript message arrived: jsCallbackHandler") default: return } } }1 WKUserContentController の生成
WKUserContentController
はWKWebViewConfiguration
に格納する必要があるので、まずはインスタンスを生成します。
2 WKUserContentController にコールバックハンドラを登録
WKUserContentController
のadd関数を用いて、JavaScript
から実行したい関数を持つクラスインスタンス(WKScriptMessageHandler
プロトコルに準拠したクラス)を第一引数に設定し、コールバックの判別に利用するためのString
をname引数に設定します。
このadd関数は何度も実行できるので、複数のコールバックを処理したい場合はname引数を変更して実行すれば、後述するコールバック関数内で判定することができます。
3 WKWebViewConfiguration に生成した WKUserContentController を登録する
生成した
WKUserContentController
インスタンスは、WKWebViewConfiguration
のuserContentController
プロパティに格納します。
4 WKScriptMessageHandler のデリゲートを記載
上記
ViewController
はデリゲート先としてWKUserContentController
に渡され登録されているので、WKScriptMessageHandler
プロトコルに準拠させる必要があります。
5 JavaScript から呼び出されるコールバックハンドラ関数を記載
WKScriptMessageHandler
プロトコルに準拠させるために、userContentController関数
を実装します。この関数を実装する事で、Javascript
からのコールバックを受け付けることができるようになります。JSからは下記のように、②の箇所のadd関数にて
name引数
に指定したコールバックを実行します。webkit.messageHandlers.jsCallbackHandler.postMessage("Message from Javascript");コールバックハンドラ内では
message.name
プロパティでコールバック名を取得することができるので、サンプルコードのようにswitch文等で判定する事で、処理を分岐させる事ができます。
検証Playground
検証環境
Mac: 10.13.6
XCode: 10.1
Swift: 4.2.1
参考ドキュメント
公式 WKWebView ドキュメント
公式 WKWebViewConfiguration ドキュメント
公式 WKUserContentController ドキュメント
- 投稿日:2020-07-04T11:05:30+09:00
【Swift】WKWebViewの基本的な使い方
下記ブログの転載です!
https://rc-code.info/ios/post-241/iOSにて、Webページを表示する必要があったので、
WKWebView
の基本的な使い方を備忘録。
WKWebView の使い方
WKWebView
の基本的な使い方です。
下記が公式のサンプルコードです。WKWebView を利用する際は
UIKit
とWebKit
を import します。
WKWebView の initialize はCGRect
とWKWebViewConfiguration
を引数にとります。
該当するURLページを開くには、WKWebView のload関数
を実行します。import UIKit // 1 WebKit の import import WebKit class ViewController: UIViewController { var webView: WKWebView! override func loadView() { // 2 WKWebViewConfiguration の生成 let webConfiguration = WKWebViewConfiguration() // 3 WKWebView に Configuration を引き渡し initialize webView = WKWebView(frame: .zero, configuration: webConfiguration) // 4 WKUIDelegate の移譲先として self を登録 webView.uiDelegate = self // 5 WKNavigationDelegate の移譲先として self を登録 webView.navigationDelegate = self // 6 view に webView を割り当て view = webView } override func viewDidLoad() { super.viewDidLoad() // 7 URLオブジェクトを生成 let myURL = URL(string:"https://www.apple.com") // 8 URLRequestオブジェクトを生成 let myRequest = URLRequest(url: myURL!) // 9 URLを WebView にロード webView.load(myRequest) } } // MARK: - 10 WKWebView ui delegate extension ViewController: WKUIDelegate { // delegate } // MARK: - 11 WKWebView WKNavigation delegate extension ViewController: WKNavigationDelegate { // delegate }
1 WebKit の import
WebView関連のコードを扱うには
WebKit
をimport
する必要があります。
冒頭にimport WebKit
を記載すると、XcodeにてWebView関連の補完が効くようになるかと思います。2 WKWebViewConfiguration の生成
WKWebViewConfiguration
はWKWebView
の初期化時に参照される設定プロパティが含まれるクラスです。
WKWebViewConfiguration
を使用すると、Webページがレンダリングされるまでの時間、メディア再生の処理方法、ユーザーが選択できるアイテムの細分性、およびその他の多くのオプションを決定できます。
WKWebViewConfiguration
は、WKWebView
が最初に初期化されたときにのみ使用されます。このクラスを使用して、WKWebView
の作成後にその設定を変更することはできません。3 WKWebView を initialize
WKWebView
の初期化にはframe引数にWebViewのサイズ、configuration引数に生成したWKWebViewConfigurationのインスタンスを引き渡します。4 WKUIDelegate の移譲先として self を登録
WKWebView
のuiDelegate
プロパティにself
をセットする事で、インターフェースに関わるWebViewの関数をクラス内で扱う事ができるようになります。5 WKNavigationDelegate の移譲先として self を登録
WKWebView
のnavigationDelegate
プロパティにself
をセットする事で、振る舞いに関わるWebViewの関数をクラス内で扱う事ができるようになります。6 view に webView を割り当て
生成した
WKWebView
のインスタンスをControllerのviewに割り当てます。7 URLオブジェクトを生成
表示したいURLのStringをURLクラスのstring引数に指定し、インスタンスを生成します。
8 URLRequestオブジェクトを生成
生成したURLクラスのインスタンスをURLRequestクラスのurl引数に指定し、インスタンス生成します。
9 URLを WebView にロード
WKWebView
のload関数にURLRequestインスタンスを引き渡し、実行します。
この関数を叩くことで、webViewのリクエストが走ります。10 WKWebView ui delegate
WKWebView ui delegate の部分には、
WKWebView
のインターフェースに関わるdelegate関数を記述します。
詳細は公式ドキュメント参照。
11 WKWebView WKNavigation delegate
WKWebView WKNavigation delegate の部分には、
WebView
の振る舞いに関わるdelegate関数を記述します。
詳細は公式ドキュメント参照。
実行環境
Mac: 10.13.6
XCode: 10.1
Swift: 4.2.1
参考ドキュメント
公式 WKWebView ドキュメント
公式 WKWebView ui delegate ドキュメント
公式 WKWebView WKNavigation delegate ドキュメント
- 投稿日:2020-07-04T10:48:54+09:00
【Swift】WKPreferences の minimumFontSize が効かない
下記ブログの転載です!
https://rc-code.info/ios/post-236/iOSの
WKWebViewConfigration
に設定するWKPreferences
のminimumFontSize
が効かないケースがあったので調査&備忘録。
WKWebView の使い方
WKWebView
の基本的な使い方に関しては こちら にまとめております。
合わせてご覧ください。
WKPreferences minimumFontSize の設定方法
WKPreferences
はWebビューの基本設定をカプセル化するオブジェクトです。(公式ドキュメント)
このうちminimumFontSize
はptサイズでフォントの最小サイズを決めるプロパティです。
まずは使い方を記載します。
import UIKit // ① WebKit の import import WebKit class ViewController: UIViewController { var webView: WKWebView! override func loadView() { // ② WKWebViewConfiguration の生成 let webConfiguration = WKWebViewConfiguration() // ③ WKPreferences の生成 let preferences = WKPreferences() // ④ WKPreferences の minimumFontSize プロパティに値を指定 preferences.minimumFontSize = 100.0 // ⑤ WKWebViewConfiguration に WKPreferences のインスタンスを設定 webConfiguration.preferences = preferences // ⑥ WKWebView に Configuration を引き渡し initialize webView = WKWebView(frame: CGRect(x: 150, y: 200, width: 200, height: 20), configuration: webConfiguration) // ⑦ view に WKWebView を割り当て view = webView } override func viewDidLoad() { super.viewDidLoad() loadView() webView.load(URLRequest(url: URL(string: "https://www.apple.com/")!)) } }
上記のように、まず
WKPreferences
のインスタンスを生成し、このプロパティであるminimumFontSize
に最小サイズにしたいフォントサイズをpt換算で指定します。
そして
WKPreferencesインスタンス
をWKWebViewConfiguration
にセットし、このWKWebViewConfiguration
をWKWebView
の設定として使います。
minimumFontSize が効かないケース
さて本題ですが、このWebViewで様々なサイトを見てみると、
minimumFontSize
を設定しているにも関わらず、指定フォントサイズ以下なってしまう場合が見受けられます。検証した結果、この事象にはCSSの
text-size-adjust
というスタイルが影響していることが分かりました。
text-size-adjust スタイルとは?
text-size-adjust
(ベンダープレフィックスだと-webkit-text-size-adjust
) は、一部のデバイスで使われるテキストの自動拡大アルゴリズムを制御するスタイルです。
対応していないブラウザーはこのプロパティを無視します。一部のモバイル端末には、縦向き (Portrate) と横向き (Landscape) が切り替わった際に文字サイズを自動調整する機能があり、
text-size-adjust
はこの自動調整を制御します。
text-size-adjust が設定されると minimumFontSize が効かなくなる
検証を行なった結果、
text-size-adjust
によって縮小されたサイズはminimumFontSize
によって制限されたフォントサイズよりも小さくなることが分かりました。念の為、その他のスタイル指定でフォントサイズの制限が無視されないか検証しています。
検証内容
最下部 Playground の Resources ディレクトリに様々なスタイル定義によるフォントサイズ変更を含んだHTMLファイルを用意しました。
minimumFontSize
を設定した WKWebViewにて、このHTMLをそれぞれ表示した結果、text-size-adjust
を設定したHTMLのみ、minimumFontSize
で指定した値よりフォントサイズが小さくなりました。
下記画像が、
minimumFontSize
に100
を設定し、上部テキストに様々なスタイル定義で40px
相当のフォントサイズを指定した画像です。
下記テキストは比較用のプレーンなテキストです。見た通り、スタイルで指定された
40px
を無視し、minimumFontSize
に指定されている100pt
相当の大きさで表示されています。
変わって次の画像が
text-size-adjust
にを指定した時の画像です。こちらの上部テキストでは、スタイルで指定された
40px
が無視され、minimumFontSize
に指定されている100pt
が適用されるはずですが、text-size-adjust
に指定している10%
が適用され、4px (40pxの10%)
相当の大きさになっています。
まとめ
全ての要素・スタイルを検証できているわけではないので確実ではないですが、
WKPreferences
のminimumFontSize
を指定しているのにフォントが想定以下のサイズになってしまうようであれば、text-size-adjust
の設定を疑ってみるのが良いかもしれません。
検証Playground
検証環境
Mac: 10.13.6
XCode: 10.1
Swift: 4.2.1
参考ドキュメント
WebKit
WKWebViewConfiguration
WKPreferences
text-size-adjust