初心者でもできるSDLアプリの作り方、中級編
Smart Device Link対応スマホアプリを、Web系技術でつくってみた
2019年10月25日 18時00分更新
クルマとスマホをつなぐ規格である「SDL」。賞金総額100万円の大規模なアプリコンテスト「SDLアプリコンテスト2019」が今年も開催されるが、実はSDL対応アプリを作るのは、それほど難しいことではない。
極めて簡単で、1行もプログラムを書いたことがない人でも楽勝!
――とまでは言えないが、本連載ではこれから、SDLとはどういったものなのか、対応アプリはどうやって作ればいいのかを解説する。そのなかで、基本的な要素のサンプルコードは掲載していくので、それらを参考に(もっと言えばコピペ)しつつ、ぜひ自分の思い付いたアイデアを実現していただきたい。
「Smart Device Link(以降SDLと記載)は、Androidネイティブアプリ、もしくはiOSネイティブアプリを開発する必要があるから、Webアプリ開発者の私にとっては、ハードルが高い」と耳にすることがよくあります。
たしかにそうなのですが、SDL対応アプリは、ほぼほぼWeb系技術でつくることもできるのです。その手法を紹介します。
テンプレートモードとプロジェクションモードの違いとは?
まず、SDLアプリの開発には、大きく2つのアプリ開発モードがあります。テンプレートモードとプロジェクションモードです。テンプレートモードとは、十数種類程度のテンプレートレイアウトがSDL規格であらかじめ定められていて、そこにボタンや画像、テキストラベルなどの、パーツごとの内容を定義していくような開発手法となります(参考 https://smartdevicelink.com/en/guides/android/displaying-a-user-interface/main-screen-templates/)。
テンプレートモードは、SDL対応車載器が各社から販売され、それらの画面サイズが大きく異なったり、たとえば縦長画面や、丸みを帯びた液晶画面がでてきた場合も、開発者がそれぞれのレイアウトを意識することなく、見た目が美しく整えられる互換性の高いモードです。
例として、GRAPHIC WITH TEXTというレイアウトを紹介します。
日本国内で、縦長のSDL車載器はまだ発売されていません。テンプレートモードをわかりやすく説明するため、筆者の推測によるイメージです。
テンプレートモードは、シンプルな動作のみに整理整頓されているため、SDL対応車載器側のCPUやGPU処理能力への依存も小さいと推測でき、数年前の車載器から数年後の車載器間でも、互換性が高いともいえるでしょう。
対して、プロジェクションモードとは、SDL対応車載器のディスプレイをスマホの外部ディスプレイのように使う開発モードです。
車載器のディスプレイ形状やサイズによる挙動の違いを、スマホアプリ側で吸収する必要があるのですが、ボタンを自由に配置できたり、動画を再生できたり、自由度は高いです。
プロジェクションモードは、スマホのCPUやGPU性能に大きく依存する仕組みとなっていいます。そのため、例えば新車を購入してから10年が経ち、SDL対応車載器が旧いものになったとしても、スマホさえ新しければ最新のスマホアプリが動く可能性が高い、クルマとつながるアプリの仕組みとして、よく考えられていると言えるでしょう。
ただし、現時点ではFPS(描写コマ数)がそれほど高くない可能性があります。また、運転中はアニメーション表示などは制限されたり、車載器とスマホの接続が転送速度の関係から、BluetoothやWi-Fiに非対応で、USBのみに制限される可能性もあります。
JavaScriptでできたWebアプリを車載ディスプレイで表示する
さて、ここで本題の「Web系技術でつくってみた」に戻りますが、察しのよい読者なら、もうお気づきかと思います。
プロジェクションモードを選び、スマホアプリ側で外部ディスプレイに表示するコンポーネントにWebViewを用いると、Web系技術(HTML5とJavaScript)を主として、SDL対応スマホアプリを開発することができるのです。
今回は、Androidアプリをベースにその開発方法を紹介しますが、iOSでもアプローチは大きく変わりません。
まず、仕上がりイメージです。
https://hisayan.github.io/sdl_android_webview/
クルマのスピードに応じて、光の中を走るようなエフェクトがかかるようなアプリをつくりました。ソース等も見ていただくとわかりますが、普通にブラウザで動く、JavaScriptでできたWebアプリです。デモ的にPCブラウザ内で動かすために、スピードのデータはサンプルデータをJavaScript内に保持させています。SDLアプリのWebView内で動かす場合は、SDLからスピードデータが更新される仕組みとなっています。
これをAndroidアプリの、WebView内で動かしてみます。
完成したソースコードは、
https://github.com/hisayan/sdl_android_webview/
こちらにありますので、こちらをAndroid Studioなどにインポートして開くと、そのまま動くようになっています。
このアプリのメインソースは、ほぼ
こちらのファイルにまとまっています。
今回はWebViewに関わるところを重点的に紹介します。まずsimpleブランチをご確認ください。プロジェクションモードで外部ディスプレイとして表示される、WebViewだけが定義された、SdlRemoteDisplayを準備します。
public static class MyDisplay extends SdlRemoteDisplay{
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stream);
this.webView = findViewById(R.id.webView);
this.webView.setWebViewClient(new WebViewClient());
this.webView.getSettings().setJavaScriptEnabled(true);
String userAgent = this.webView.getSettings().getUserAgentString();
this.webView.getSettings().setUserAgentString(userAgent + " SmartDeviceLink");
// インターネット上の HTML も表示できる
this.webView.loadUrl("https://www.google.co.jp/");
}
}
このようにするだけで、SDLアプリとして、車載ディスプレイ(HMI)にWebページを表示することができます。サンプルとして、GoogleのURLにしていますが、こちらを任意の自身のWebアプリのURLにするだけで、なんとSDLのHMIに表示できるのです。とても簡単ですね。
次に、SdlRemoteDisplayを表示します。private void startProxy()関数の中ほどで、
videoStreamShow();
という関数を呼び出しています。
SDLアプリを起動し、SDLデバイスと通信が確立したら、SDLデバイスの画面サイズを取得。取得した画面サイズに合わせて、先ほど準備したSdlRemoteDisplayを表示するだけの、シンプルなプログラムです。
private void videoStreamShow() {
if (sdlManager.getVideoStreamManager() != null) {
sdlManager.getVideoStreamManager().start(new CompletionListener() {
@Override
public void onComplete(boolean success) {
if (success) {
// SDL HMIの画面サイズを取得し、そのサイズで、sdlRemoteDisplayを準備する
VideoStreamingCapability videoStreamingCapability = (VideoStreamingCapability) sdlManager.getSystemCapabilityManager().getCapability(SystemCapabilityType.VIDEO_STREAMING);
VideoStreamingParameters videoStreamingParameters = new VideoStreamingParameters();
videoStreamingParameters.getResolution().setResolutionWidth(videoStreamingCapability.getPreferredResolution().getResolutionWidth()); // 800
//
videoStreamingParameters.getResolution().setResolutionHeight(videoStreamingCapability.getPreferredResolution().getResolutionHeight()); // 350
// Capavility から変える350 というパラメーターが不正。実サイズは480。DL BootCamp 側のバグと思われるため強制的に480に設定
videoStreamingParameters.getResolution().setResolutionHeight(480);
sdlManager.getVideoStreamManager().startRemoteDisplayStream(getApplicationContext(), MyDisplay.class, videoStreamingParameters, false);
} else {
Log.e(TAG, "Failed to start video streaming manager");
}
}
});
}
}
実行すると、Googleのホームページが、SDL車載機に表示されたかと思います。
もちろんSDL車載機はタッチ対応ですので、Linkがついている箇所をタッチすると、きちんとそのページに遷移します。
車両情報をWebアプリで使う方法
さてGoogleの画面表示だけだと、せっかくのSDLなのに車両情報をつかっていないので、なんだか不完全燃焼感がありますね。
続いて車両情報をWebアプリで使う方法についても、簡単に触れておこうと思います。
masterブランチを開いてみてください。そして、さきほどのSdlRemoteDisplayの箇所をみてください。
public static class MyDisplay extends SdlRemoteDisplay{
private SpeedBroadcastReceiver speedBroadcastReceiver = null;
private Context context;
private WebView webView;
public class SpeedBroadcastReceiver extends BroadcastReceiver {
private MyDisplay myDisplay;
public SpeedBroadcastReceiver(MyDisplay myDisplay) {
this.myDisplay = myDisplay;
}
@Override
public void onReceive(Context context, Intent intent)
{
if (this.myDisplay.webView != null) {
// ブロードキャストが呼ばれた時
String speed = String.valueOf(intent.getIntExtra("SPEED", 0));
this.myDisplay.webView.loadUrl("javascript:setSpeed(" + speed + ");");
}
}
}
public MyDisplay(Context context, Display display) {
super(context, display);
this.context = context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stream);
this.webView = findViewById(R.id.webView);
this.webView.setWebViewClient(new WebViewClient());
this.webView.getSettings().setJavaScriptEnabled(true);
String userAgent = this.webView.getSettings().getUserAgentString();
this.webView.getSettings().setUserAgentString(userAgent + " SmartDeviceLink");
this.webView.loadUrl("file:///android_asset/index.html");
// ブロードキャストを設定
if(this.speedBroadcastReceiver == null) {
// ローカルブロードキャスト用IntentFilterを生成
IntentFilter intentFilter = new IntentFilter(SdlService.BROADCAST_SPEED);
// ローカルブロードキャストを受け取るレシーバを設定
this.speedBroadcastReceiver = new SpeedBroadcastReceiver(this);
// ローカルブロードキャストを設定
LocalBroadcastManager.getInstance(this.context).registerReceiver(this.speedBroadcastReceiver, intentFilter);
}
}
}
ここでSdlRemoteDisplayがローカルブロードキャストを受け取るレシーバーを準備しています。また、WebView内でインターネット上のWebページを開いてもいいのですが、便宜上、Androidアプリのassetとして準備したWebアプリを表示するようにしています。
このassetのhtmlとJavaScriptは、
https://hisayan.github.io/sdl_android_webview/
こちらと同じものになっています。
ではレシーバーをつくったので、それに応じたローカルブロードキャストを送信しましょう。スピード情報のみを取得&送信しています。
sdlManager.addOnRPCNotificationListener(FunctionID.ON_VEHICLE_DATA, new OnRPCNotificationListener() {
@Override
public void onNotified(RPCNotification notification) {
OnVehicleData onVehicleDataNotification = (OnVehicleData) notification;
Double speed = onVehicleDataNotification.getSpeed();
if (speed != null) {
Log.i("SdlService", "Speed was updated to: " + speed);
Intent localBroadCastIntent = new Intent(SdlService.BROADCAST_SPEED);
localBroadCastIntent.putExtra("SPEED", speed.intValue())
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(localBroadCastIntent);
}
}
});
こちらはすこしSDLの命令を書き加えるだけで、エンジン回転数や水温、ガソリン残量など、さまざまなデータをSDLから取得し、Webアプリに送信することができます。
SDL車両情報を送信するプログラムも、pythonディレクトリに用意されています。
Python3が動くPC/Macを、SDL BootCampのWi-Fiに接続し、
$ python3 ./python/simulateSpeed.py
と実行してみてください。
その後、SDLアプリを実行しましょう。
SDL BootCampの仕様かと思いますが、先に車両データを送信しつづけた状態で、SDLアプリを動かさないと、うまくいかないケースがあるので、ご注意ください。Androidアプリにデータが届いていないような感じのときは、SDL BootCampの再起動からお試しください。
どんどん表現領域を広げているSDL
さて車両データを利用したい場合は、ブロードキャストとかレシーバとか、Webアプリ開発者の手に馴染みにくい概念がでてくるので、開発に二の足を踏んでしまうところかもしれません。
ですが、たとえばスピードとエンジン回転数等を取得し送信するベースとなるAndroidアプリを(ここはAndroid Javaに詳しい人を頼りながら)一度つくっておいて、そのWebアプリの置き場所のURLを決めてしまえば、その後は、Webアプリ開発者だけでも、任意のURLにSDL対応Webアプリをおいておくだけで、さまざまなアプリを動かすことができるます。Android Studioなど、Javaの開発環境を一切必要とせず、JavaScriptを書きかえるだけで、SDLアプリの挙動を変えることができるようになるのです。SDL Webアプリを、SDL Androidアプリで、Wrapする感じですね。
そして、このようなWrapした仕組みにすることで、Androidでも、iOSでも、まったく同じSDL Webアプリが動くような仕組みも、比較的かんたんに用意することもできます。
そうです、これでなんちゃって、SDL Webハイブリッドアプリプラットフォームのできあがりです。
さて、SmartDeviceLinkのオープンソースの活動では、JavaScript SDKの開発も始まっています(WebViewアプリ経由でなくとも、WebアプリがSDL対応車載器で動かせる仕組み。参考 https://github.com/smartdevicelink/sdl_javascript_suite)。
また、SDL対応車載器そのもののHMI (Human Machine Interface)についても、Qt(キュート)という C++ベースの仕様も準備されていますが、HTML5の仕様でも開発できるようになっています。
開発言語のメリット・デメリットはいろいろありますが、HTML5 + JavaScriptという組み合わせは、その表現領域をどんどん伸ばしており、また開発できる人口も多く、なにより各種WebAPIエコノミーと親和性が高いというメリットがあります。
今後、各種APIがMashupされた、今までに見たことがないようなSDL対応車載アプリが、どんどんでてくることも期待しています。
「クルマとスマホをなかよくする SDLアプリコンテスト2019」
主催:SDLアプリコンテスト実行委員会(事務局:角川アスキー総合研究所)
協力:SDLコンソーシアム日本分科会、株式会社ナビタイムジャパン
後援(予定): 独立行政法人国立高等専門学校機構、一般社団法人コンピュータソフトウェア協会ほか
応募締切:2019年10月31日(木)24:00
募集内容:エミュレーターか開発キット上で開発したSDL対応アプリ(既存アプリの移植、新規開発)
募集対象:年齢、性別、国籍等不問。個人・チームどちらでも応募可
応募方法:プレゼンシートと動作解説動画をWebフォームで応募
審査:審査員が新規性、UX・デザイン、実装の巧みさ等で評価
最終審査会:2019年11月22日(金)
審査員:暦本純一(東京大学情報学環教授)、川田十夢(AR三兄弟長男)、鈴木朋子(ITジャーナリスト・スマホ安全アドバイザー)ほか
グランプリ:賞金50万円+副賞
特別賞(5作品):賞金各10万円
公式サイト:http://sdl-contest.com/
(提供:SDLコンソーシアム)
この連載の記事
-
第9回
sponsored
スマホが当たり前になった時代のクルマはすべてこうなる! -
第8回
sponsored
函館高専もSOMPOも、実はごく短期間で一気に制作! -
第6回
sponsored
後部座席の子どもの様子がわかる「こどもカメラ」はただのカメラじゃない! -
第5回
sponsored
ギアやシフトレバーの情報など、車のデータを取得してみよう! -
第4回
sponsored
まずはSDLの車載機シミュレーター上に画面を出してみよう -
第3回
sponsored
賞金50万円を受賞したグランプリ作品「Instaride」はどう企画されたのか? -
第2回
sponsored
SDLアプリの開発には何が必要なのか? -
第1回
sponsored
スマホと車・バイクを「便利なまま」つなげるSDLって知ってる? -
sponsored
スマホと車・バイクを連携させる新規格SDLのすべて - この連載の一覧へ