Just another WordPress.com site

2011/07/23” タグの投稿

[HTML Format]:

[2011/07/23 23:50:19]: https://www.google.com/adsense/g-app-single-1?sourceid=aso&subid=jp-ja-et-ashp-regionala&medium=link

——————-


[HTML Format]:Androidで動く HTMLとJavaScriptで作る電子書籍アプリ Android De

[2011/07/23 23:16:47]: http://crocro.com/write/android/wiki.cgi?p=Android%A4%C7%C6%B0%A4%AF+HTML%A4%C8JavaScript%A4%C7%BA%EE%A4%EB%C5%C5%BB%D2%BD%F1%C0%D2%A5%A2%A5%D7%A5%EA

  • はてなブックマーク - Androidで動く HTMLとJavaScriptで作る電子書籍アプリ - Android Dev - CroCro
  • このエントリーを含むはてなブックマーク

——————-

Androidで動く HTMLとJavaScriptで作る電子書籍アプリ

Android Dev – CroCro

Androidで動く HTMLとJavaScriptで作る電子書籍アプリ

2011/01/13 ページ作成
2011/01/19 最終更新
クロノス・クラウン合資会社
柳井政和
HP:http://crocro.com/
Twitter:http://twitter.com/ruten
はじめに

本資料とプログラムは、2011/01/16のSwapSkillsの勉強会用に作成したものです。この勉強会に、講師として登壇することになりましたので、Android+JavaScriptという内容で用意しました。

Androidのアプリケーションは、WebViewというクラスを使うことで、簡単にHTMLファイルを表示させることができます。このWebViewは、Androidのブラウザと同じで、WebKitをレンダリングエンジンとして使用したものです。

この仕組みと、既存のWebページ作成技術を利用して、Androidの簡単なアプリケーションを作成してみようというのが今回の主眼です。また、その一環として、JavaScriptを軽く学んでみようと計画しています。

サンプルのソースコードは、Android側が50行、HTML側が300行程度の短いものです。内容的には、多岐に渡っていますが、やっていること自体はかなり単純です。

一応「電子書籍」と書いていますが、「なんちゃって電子書籍」といった感じの「電子書籍風アプリ」ということでご理解いただければと思います。

というわけで、資料とプログラムを公開しておきますので、ご自由に利用していただければと思います。

作成したアプリの動作確認

どんな感じになっているのか、Youtubeの動画で確認できるようにしました。

また、ブラウザ上で確認できるようにもしました。あまり多くのブラウザで検証していないので、バグがあるかもしれません。そこはご愛嬌ということで。

HTML部分をブラウザから確認。

簡単な操作説明もしておきます。

<< 最後のページに
前のページに
>> 最初のページに
□+ 50%拡大
□□ 画面にフィット
□- 50%縮小
画像をドラッグ 表示位置移動
タイトル ページ数と書籍名を表示

勉強会用資料

PDFとして作成した資料です。Googleドキュメントにアップしましたので、自由に閲覧することができます。

内容的には、以下のことに触れています。

Androidの開発環境設定
AndroidとiPhoneの比較。ビジネスの主体(AppleとGoogleのスタンスの違い)
HTMLとJavaScriptで電子書籍アプリを作成
JavaScriptの書き方、関数の書き方・呼び出し、自分で作る変数など。
プログラムの準備 仕様の策定(UIと機能の決定、設計図、策定した仕様の関数を整理など)
アプリケーションの完成

Androidのプロジェクトを、ZIPファイルで固めてアップしていますので、Androidの開発を行っている方は、自分の環境で動作を確かめることもできます。サイズは2MBほどです。

MangaJSプロジェクトをダウンロード

Android側ソースコード

以下、Android側のソースコードです。短いです。

package com.crocro.android.mangaJS;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

public class MangaJS extends Activity {
WebChromeClient mWebChromeClient = new WebChromeClient() {
// document.titleの変更を実装
@Override
public void onReceivedTitle (WebView view, String title) {
MangaJS.this.setTitle(title);
}
};

// メイン部分
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(mWebChromeClient);
webView.loadUrl(“file:///android_asset/index.html”);
setContentView(webView);
}
}
以下、簡単な解説を行っておきます。

基本的には「メイン部分」の処理が全てです。アプリ起動時に呼び出される「onCreate」メソッド内で、「WebView」クラスを初期化して、画面に貼り付けています。

作成した「WebView」では、「JavaScriptの許可」(getSettings().setJavaScriptEnabled(true))、「WebChromeClientの設定」(setWebChromeClient(mWebChromeClient))、「URLの読み込み」(loadUrl(“file:///android_asset/index.html”))を行っています。「file:///android_asset/」というのは、Androidアプリのプロジェクト内の「assets」フォルダになります。

「WebChromeClient」についても補足しておきます。ここでは「mWebChromeClient」として、「document.titleの変更」の実装を行っています。これらの設定をしなければ、「WebView」を画面に貼り付けても、JavaScriptからタイトルを変更することはできません。

HTML側ソースコード

以下、HTML側のソースコードです。少し長めです。

/* Basic */
body {
margin: 0px;
padding: 0px;
height:100%;
overflow: hidden;
}

/* Tool range */
#tools {
height: 50px;
overflow: hidden;
text-align: center;
}
#tools input {
margin: 0px;
padding: 0px;
height: 100%;
font-size: 20px;

/* fit for a tool range */
width: 14.28%;
width: expression(document.body.clientWidth / 7); /* for IE */
}

/* Page range */
#page {
background: silver;
margin: 0px;
padding: 0px;
overflow: scroll;

/* fit for a page range */
position: absolute;
top: 50px;
left: 0;
right: 0;
bottom: 0;

/* for IE */
width: 100%;
height: expression(document.body.clientHeight – 50);
}
#pageImg {
position: absolute;
cursor : move;
}

<!–
//==================================================
// 変数
var bookTitle = "マンガでわかるJavaScript"; // 本のタイトル
var pageMax = 9; // ページ数 全体
var pageNow = 1; // ページ数 現在
var screenW = 0; // 画面サイズ 横幅
var screenH = 0; // 画面サイズ 高さ
var imageW = 0; // 画像サイズ 横幅
var imageH = 0; // 画像サイズ 高さ
var rateFit = 0; // 倍率 フィット
var rateNow = 0; // 倍率 現在

var rateStep = 0.5; // 倍率の変動量

//==================================================
// 「ページ読み込み時の初期化」関数
function myLoad() {
// IEでブラウザ起動直後に値が取得できないバグ対策
if ($("#page").width() == 0 || $("#page").height() == 0) {
window.setTimeout(myLoad, 100);
return;
}

// スクロール・バーのサイズを計算
var scrollBarSize = getScollBarSize();

// 画面サイズの初期化
screenW = $("#page").width() – scrollBarSize;
screenH = $("#page").height() – scrollBarSize;

// 1ページ目を読み込み
pageNow = movePage(1);
}

// スクロール・バーのサイズを取得
function getScollBarSize() {
// スクロール・バーのサイズを計算
var obj = $("#calcScrollBar").get(0);
var doc = obj.contentWindow.document;

var iframeHtml = $("#calcScrollBarIn").html()
.replace(//g, “”); // HTML用文字列取得
doc.write(iframeHtml); // iframeの中身を作成

var docEle = doc.documentElement;
var scrollBarW = obj.width – docEle.clientWidth;
var scrollBarH = obj.height – docEle.clientHeight;

if (scrollBarW <= 8) scrollBarW = 8; // Androidバグ対策
if (scrollBarH <= 8) scrollBarH = 8; // Androidバグ対策

$("#calcScrollBar").hide(); // 計算が終わったので隠す

return Math.max(scrollBarW, scrollBarH); // 大きい方を戻す
}

//==================================================
// 「ページ移動」関数
function movePage(pageNo) {
// エラー処理
if (pageNo pageMax) {
// ページ範囲外なので、戻り値を戻して終了
return pageNow;
}

// 画像終了時のイベント処理用関数を設定
var obj = $(“#pageImg”).get(0);
obj.onload = function() {
// 画像サイズの初期化
imageW = this.width;
imageH = this.height;

// 倍率 フィットの計算
var rateW = screenW / imageW;
var rateH = screenH / imageH;
rateFit = (rateW < rateH) ? rateW : rateH;

// 倍率 現在の設定と、倍率の変更
rateNow = changeRate(rateFit);
};

// 画像の読み込み
obj.src = "page/" + pageNo + ".gif";

// タイトルの表示
document.title = "[" + pageNo + "/" + pageMax + "] "
+ bookTitle;

// 戻り値を戻して終了
return pageNo;
}

//==================================================
// 「倍率変更」関数
function changeRate(rateNo) {
// エラー対策(10%を最小値にする)
if (rateNo

<input type="button" value="<<input type="button" value="” onClick=”backPage();”
>>” onClick=”firstPage();”
>

<!–

html,body,div {
margin: 0;
padding: 0;
}
#box {
width: 200px;
height: 200px;
}

–>

以下、プログラマ向けの技術的な解説を行っておきます。

CSSの中に、以下のような行があります。

width: expression(document.body.clientWidth / 7); /* for IE */
この「expression(~)」というのは、IEだけで動作する設定です。内部がJavaScriptとして解釈されて実行されます。ブラウザ間の表示の違いを吸収させるために設定しています。

次に「IEでブラウザ起動直後に値が取得できないバグ対策」です。ブラウザ起動とともにファイルを読み込んだ際、IEでは、onLoad直後にwidthとheightの値が0になってしまうというバグがあったので、下記のように、遅延処理させています。通常はリンクからたどるか、ブラウザを開いた状態でブックマークから閲覧すると思うので、あまり遭遇しない挙動だと思います。

以下のように、正常に値が取れない際は、100mscecずつ待って、初期化処理を行うようにしています。

// IEでブラウザ起動直後に値が取得できないバグ対策
if ($(“#page”).width() == 0 || $(“#page”).height() == 0) {
window.setTimeout(myLoad, 100);
return;
}
次の「スクロール・バーのサイズを取得」では、自動でスクロール・バーのサイズを計算して、幅を取得するようにしています。

「iframeHtml = $(“#calcScrollBarIn”).html().replace(/<!–|–>/g, “”); doc.write(iframeHtml);」という部分は、ID「calcScrollBarIn」の中身をドキュメントから取得して、iframeに流し込むための処理です。外部のHTMLファイルを用意するのが面倒でしたので、同じファイル内に記述しました。

さて、実はこの「スクロール・バーのサイズ取得」関数は、IEやChromeなど、PC向けのブラウザでは正しく動作しますが、肝心のAndroidでは正しく動作しませんでした。原因は、「obj.width」「obj.height」の値が、PCのブラウザのように、スクロール・バーの内側のサイズで取得できないためでした。

Androidでは、そのまま200ピクセルと戻ってきて、スクロール・バーの内側のサイズにはなりませんでした。そのため、Androidでは8ドット決め打ちで、スクロール・バーのサイズを戻すようにしています。

// スクロール・バーのサイズを取得
function getScollBarSize() {
// スクロール・バーのサイズを計算
var obj = $(“#calcScrollBar”).get(0);
var doc = obj.contentWindow.document;

var iframeHtml = $(“#calcScrollBarIn”).html()
.replace(//g, “”); // HTML用文字列取得
doc.write(iframeHtml); // iframeの中身を作成

var docEle = doc.documentElement;
var scrollBarW = obj.width – docEle.clientWidth;
var scrollBarH = obj.height – docEle.clientHeight;

if (scrollBarW <= 8) scrollBarW = 8; // Androidバグ対策
if (scrollBarH <= 8) scrollBarH = 8; // Androidバグ対策

$("#calcScrollBar").hide(); // 計算が終わったので隠す

return Math.max(scrollBarW, scrollBarH); // 大きい方を戻す
}
最後は、スマートフォン向けの処理です。

スマートフォンでは、画面内のオブジェクトに触れた場合、「MouseDown」「MouseUp」といったイベントではなく、「TouchStart」「TouchEnd」といったイベントが発生します。

そのため、これらのスマートフォン向けのイベントを、PCのブラウザのイベントにバイパスするための仕掛けを用意しています。

以下、その部分のソースコードの抜粋です。

// スマートフォンのタッチイベントからマウス用イベントを生成
function emulateMouse() {
event.preventDefault();
return event.touches[0]; // マルチタッチの1番目
}

というわけで、350行程度の小さなアプリケーションですが、いろいろな技術を詰め込んでみました。参考になりましたでしょうか?