[Android]テスト勉強会

Agenda

・Androidのセキュリティと品質保証の問題について
谷口 岳 様 (タオソフトウェア株式会社 代表取締役)
・ユーザとベンダで生討論!みんなでつくる「受入れテストガイドライン」
株式会社電通プラットフォームビジネス局開発部
・CI導入ライブ-jenkins ci server
h.suehiro
・Lightning Talks
「Androidアプリリリース作業の効率化(2)」神原 健一@korodroid
「Hello,CI. Jenkins met gerrit.」/テスト部 gerrit導入 進捗報告
・三大リモートテストサービス 東海の大決闘!

Summary

「動かない+儲からない」で有名なAndroidのアプリケーション。現場レベルで言うと、テスト工数が占める割合が他のプロダクトに比べて多い気がします。限られたテスト期間の中ですべての実機端末をテストするのは不可能でそこをどのようなアプローチで解決していくかというのがこの講演の趣旨となります。
一方で電通の方の講演はテストから一部脱線していましたが、非常に興味深かったので記事に残しておきます。

ユーザとベンダで生討論!みんなでつくる「受け入れテストガイドライン」

まず、電通プラットフォームビジネス局開発部の説明。主にスマートテレビやスマートフォンの開発を行っており、自社製のアプリ(ミテレ等)を企画し開発会社に依頼をしたり、一般企業から制作依頼を受けて、要件定義から基本設計までを行い開発会社に依頼をするような業務を行っているそうです。土曜日の講演だったのですが、金曜日も相当遅くまで働いていたっぽかったです。


・どうやったら売れるアプリがつくれるのか?
→すごく抽象化されていて一意となるような答えがありません。マーケティングサイドから考えるともちろんアプリケーションのコンセプトももちろん大事なのですが、コンセプトと同じくらい「ユーザビリティー」の大切さを現場レベルで実感しているそうです。しかもそのユーザビリティーというのは評価できる指標がない(定量化できない)ことが問題である感じているようです。
人間の知覚に関わる要素は、用件として定量化できない。
例えば、体操競技では技という芸術を難度という観点から定量化されています。(体操競技の技名一覧)同様のアプローチでユーザビリティーも定量化できないのか、そうすることでアプリケーション開発の見積もりに「工数」という概念が通常用いられますが、こんなユーザビリティーをつけるといくらという見積もり方法も出てくるかもしれません。

また、WEBとスマートフォンのアプリケーションの大きな違いについて、WEBサイト構築の仕事ではかなり依頼者からの注文が多かったりするそうです。それはWEBサイトは依頼者側も日々WEBに慣れ親しんでおり、WEBの技術を使えば何ができて何ができないかをよく認識しているからです。一方でスマートフォンのアプリケーション開発では「何が実現できるかわからない」「iPhone開発とAndroid開発はほとんど同じだと思っている」等依頼者側の認知度が低いのが問題となっている一方、制作側の自由度が高いそうです。提案資料がある程度納得感があれば、依頼者側のいちゃもんが減り要件が固まりやすいとか(笑)

三大リモートテストサービス 東海の大決闘!

ここから話はがらっと代わり、各社のリモートテストサービス紹介記事です。リモートテストサービスとはテストをしたい人が端末を持っていなくても、リモートで端末を貸し出し自分のPCから対象の端末を借りることができ、テストが実行可能となるサービスのことをさします。


リモートテストサービス NTTドコモ
<概要>
Docomo端末のリモートテスト実行環境。リモートサーバに複数の実機端末を複数台USB接続し、HTML5ベースのGUIから対象の実機を操作可能。実機の画面はWEBカメラで転送。HTML5ベースのGUIは他の人と画面をシェアできる(デモを同席していないクライアントに見せるといったことが可能)。USB端末で接続されているものの、実機は固定されているのでセンサー系のテストができない。

scirocco cloud 株式会社ソニックス
<概要>
HTML5ベースでのGUIからクラウド上にテストしたいapkファイル(アプリケーション)をUPLOADして、クラウド上でテストを行う。テスト報告書等のエビデンスまわりもしっかりサポートされている。
<補足>
TestRecoder
画面を操作しながらテストケースの作成することが可能で、再度同様のテストを実行するときには、以前保存したテストの状態からテストを復元することが可能(同じテストは二回やらなくて済みます。)一般的に出回っているこの類いのテストツールとの違いはレイアウト情報で「ボタンを押す」とかのイベントを発生させるわけではなく、IDと紐づけているのでレイアウトの変更や端末依存に耐えうることが可能です。

リモート・スマホ・レンタルサービス 株式会社カトマック
<概要>
NTTドコモが開発中のリモートテストサービスのキャリアにとらわれずテストが実施可能なもの。大きく違うところは画像データをWEBカメラで撮影しているのではなく、agentを端末に入れて画像信号を抜きとってクライアントに送信しているので超高速。
<補足>
代表取締役の久納 孝治さんはそうとう優秀なエンジニアぽいです。(SkypeにAPIを、Operaにツールを提供しているとか)この会社自体は2012/4/2に設立されています。

[Android]AdMobのjarのバージョンではまる

AdMobのjarをプロジェクトに取り込み広告を表示するためにすることを纏めました。手順は以下の通りです。

1. AdMobをダウンロードする。
2. GoogleAdMobAdsSDK-4.3.1.jarをプロジェクトに取り込み、ビルドパスを通す。
3. AndroidManifest.xmlにパーミッションを追加する。
4. Activityに広告を追加する。

AdMobをダウンロードする

以下のサイトを参考にしてみてください。
[xcode][AdMob]Google AdMob Ads SDK 4.0.2 をダウンロード

2012/3/31時点の最新のバージョンは4.3.1です。

jarをビルドパスに通す

Project下のjarを右クリックし、ビルドパスを選択 > ビルドパスに追加します。

AndroidManifest.xmlの編集

まず、広告を挿入したいActivityをcom.yusuke.sample.AdTestActivityとします。
AndroidManifest.xmlにActivityを宣言する際に以下のように設定を追加してください。

<activity 
	android:name=".front.HistoryAndFavoriteActivity" 
	android:screenOrientation="portrait" 
	android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />

ポイントは
android:configChanges=”keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize”

これが広告を動作する上で必須の設定のようです。ちなみに、APIバージョンが14(Target Name4.0)以上である必要があります。

次に以下のパーミッションを許可するようにしてください。

	<uses-permission android:name="android.permission.INTERNET"/>
	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

勿論広告なのでネットワークのアクセスは必須です。また、地域にあった広告を配信するためにロケーションに関するパーミッションも追加します。

Activityの実装

以下の通りに実装します。広告に関わるところのみの記述となっています。

package com.yusuke.sample;

import com.google.ads.AdRequest;
import com.google.ads.AdView;

public class AdTestActivity extends Activity {
	/** 変数宣言 */
	AdView mAdView;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		mAdView = (AdView) findViewById(R.id.ad);
	}
	@Override
	public void onResume() {
		mAdView.loadAd(new AdRequest());
	}
	@Override
	public void onRestart() {
		mAdView.loadAd(new AdRequest());
	}
	@Override
	public void onDestroy() {
		if (mAdView != null) {
			mAdView.destroy();
			mAdView = null;
		}
	}
}

onCreateメソッドでレイアウトファイルからインスタンス化し、onResumeメソッドで実際に更新の配信要求を出しています。また、onDestroyメソッドで広告のインスタンスを破棄します。

レイアウトファイルの定義

以下のような定義となっています。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:background="@color/light_blue"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
		<com.google.ads.AdView
			android:id="@+id/ad"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:layout_alignParentBottom="true"
			ads:adSize="BANNER"
			ads:adUnitId="your publisher id" />
</RelativeLayout>

5行目で広告用のネームスペースを宣言し、それらを13,14行目で利用します。
※パブリッシャーID
作成したアプリケーションの設定画面で閲覧可能です。

ひっかかりポイント

現在世間一般的に出回っているAndroidのAPIバージョンは10(2.3系)です。一方で広告が正常に動作するための必須条件として最新のAdMob API、即ちAndroidのAPIバージョン14(4.0系)が指定されています。
※ちなみに古いAdMob APIバージョンでは広告が配信されません。

2.3系をターゲットとしてアプリケーションを作成しても、プロジェクトのTarget Buildは4.0。うーん、Paradox…

[Android]Google Playでアプリケーションを更新する

Google Playへの登録方法は以下の記事で紹介されています。
[Android]Android Marketにディベロッパー登録してみる

また初回のアプリケーション登録方法については以下の記事で紹介されています。
[Android]マーケットにアプリケーションを登録してみる

更新したモジュールをエクスポートする

最初にGoogle Playにアプリケーションを登録する方法とほぼ同様の方法でapkファイルをエクスポートして登録を行います。

最初にGoogle Playに登録したKey Storeを利用してファイルをエクスポート

キーストアは最初に登録したapkファイルと同様である必要があるので、既存のキーストアを利用して作成します。これポイントです。最初に登録したときのキーストア情報がないとUpdateできないようです。

管理画面からアプリをアップロードする

Google Playで確認してみる

アプリケーションにアクセスすると最初のうちはエラーとなりますが、30分程度で完全に反映されます。

[Android]マーケットに登録したapkファイルでFacebookAPIを利用する方法

apkをGoogle Playで登録し、稼働確認を実施していたところFacebookの認証でクラッシュしたのでそのときの備忘録。

Key Hashの生成

通常の開発はデバッグモードで行っているので、デバッグ用のキーストアを利用して開発しているが、Google Playに登録するときには別のキーストアを発行する。これに対するKey Hashを生成し、Facebookアプリの管理ページに登録する必要がある。

まずKey Hashの生成方法だが通常の証明書付きapkファイルを出力した場合はキーストアのファイルとapkファイルが出てくる。このキーストアファイルとapkファイルを作成したときに入力したエイリアスを利用してKey Hashを生成する。

$ keytool -exportcert -keystore ${Path to key store} -validity 10 -alias ${Alias name} | openssl 
sha1 -binary | openssl base64
キーストアのパスワードを入力してください:  ******* <- Key Storeのパスワードを入力
*******************                          <- これをAndoid Key Hashとして登録する

Facebookの開発者ページにログインし、出力されたAndroid Key Hashを入力して設定を変更すると「several minutes」後に反映され、認証が通るようになります。

[Facevote]投票アプリWeb版

WEB版

機能概要→[Android]Facemash的なアプリ

Google Playに登録した「Facevote」の簡易Web版が追加されました。Ajaxが使われているのでAndroidに比べるとサクサク感がナイスです。
※2012/3/27 現在対応ブラウザはChromeのみ。
# Update 2012/3/29 Firefox対応完了

[Android]マーケットにアプリケーションを登録してみる

Androidアプリに署名をつけてエクスポートする

出力対象のプロジェクトを選択して、右クリック > Androidツール > Export Signed Application Package…と選択していきます。そして、プロジェクト名称を入力します。

※おそらく、開発中は実機でデバックを行うためにAndroidManifest.xmlで「android:debuggable=”true”」としているはずなので、「android:debuggable=”false”」にする必要があります。

必要な情報を入力していきます。

必要事項の入力が終了したら、apkファイルを出力します。これで、署名されたapkファイルが出力されました。

Google Playに登録する

マーケットに登録するためにはまずディベロッパー登録する必要があります。登録方法にすいては過去の投稿をご覧ください。→ [Android]Android Marketにディベロッパー登録してみる

まず、Google Playの管理画面にログインして、画面右下にある「アプリケーションをアップロード」を選択します。

次にapkをアップロードするよう求められるので、先ほど作成したapkファイルをアップロードします。

アップロードが完了するとそのアプリケーションの情報(バージョン、アクセスする機能等)が出てきますので、そちらを確認し、問題なければ保存を選択します。

公開するためにはアプリケーションの説明や画像が必要なので、そちらの登録を行っていきます。具体的には設定として以下の項目が用意されています。

アセットのアップロード
項目 説明
プロモーション画像 携帯のGoogle Playに表示させる画像です。
宣伝用画像 PC版のGoogle Playに表示させる画像です。
プロモーション動画 YouTubeに紹介用の動画をUPLOADしている場合にYouTubeへのリンクが設定可能です。
プライバシー ポリシー プライバシー ポリシー画面が用意されている場合はそのURLを設定することが可能です。この項目にはチェックボックスが用意されており、「今回はプライバシー ポリシー の URL を送信しない」の選択も可能です。
マーケティングの除外 「Google Play と Google 所有のオンライン/モバイル サービス以外ではアプリケーションを宣伝しません。この設定への変更が有効になるまでに 60 日程度かかることについて了承します。」のチェックが可能です。
掲載情報
項目 説明
言語 アプリケーションの言語を設定できます。複数選択が可能で、アスタリスク(*)のついている言語がデフォルトの言語となります。
Title (日本語) タイトルを設定します。
Description (日本語) 説明を設定します。
Recent Changes(日本語) 変更履歴のようなものを設定します。
Promo Text (日本語) 販促説明を設定します。
アプリケーション タイプ アプリケーションのタイプを「アプリケーション・ゲーム」から選択します。
カテゴリ カテゴリを「エンターテイメント・カスタマイズ・コミック・ショッピング・スポーツ・ソーシャル・ツール・ニュース&雑誌・ビジネス・ファイナンス・メディア&動画・ライフスタイル・ライブラリ&デモ・交通・仕事効率化・健康&フィットネス・写真・医療・天気・教育・旅行&地域・書籍&文献・通信・音楽&オーディオ」から選択します。
公開設定のオプション
項目 説明
コピー防止 端末からアプリケーションのコピーが可能かを設定します。(コピー機能は間もなく廃止される予定という注釈が表示されています。)
コンテンツのレーティング ユーザ成熟度の設定を行います。
価格設定 価格の設定です。
サポートされている端末 AndroidManifest.xmlの定義情報を得て、どの機能を有した端末で利用可能かを表示してくれます。具体的にX台の利用が可能と表示されます。

その他に連絡先情報の設定と同意事項のチェックがあります。

以上の項目を必要に応じて入力したあと、「公開」ボタンを押すとGoogle Playにアプリケーションが公開されます。

[Java]WebページをTree構造に基づいてスクレイピング

Introduction of JTidy

以前、スクレイピングするコードを書いたさいにはHTMLファイルを一旦Stringオブジェクトに変換して、divタグやらクラス属性やらでStringをパースした記憶がありますが、今回はDOMの構造に基づいて解析可能なライブラリがあったので、紹介したいと思います。そのライブラリはJTidyです。

JTidyとは

Download

こちらからダウンロードしてください。クラスパスに追加すれば、即利用可能です。

Show sample Program

日経のマーケット情報サイトから現在値・始値・高値・安値を取得するサンプルプログラムを作成してみます。
まず、プログラム作成のINPUTとして、サイトのHTMLがどのような構造から成り立っているか確認する必要があります。
Firefoxの場合⇒HTML上で右クリック > ページのソースを表示
Chromeの場合⇒HTML上で右クリック > ページのソースを表示
IEの場合⇒ツールバー > 表示 > ソース

今回のスクレイピング対象は以下のような構造をしています。(一部抜粋)

<div class="st-top_price_detail">
    <dl class="stc-part1">
        <dt class="stc-opening">始値<span class="stc-update">(9:00)</span></dt>
        <dd class="stc-opening">433</dd>
        <dt class="stc-high">高値<span class="stc-update">(9:01)</span></dt>
        <dd class="stc-high">434</dd>
        <dt class="stc-low">安値<span class="stc-update">(9:05)</span></dt>
        <dd class="stc-low">431</dd>
    </dl>
    .
    .
    .
</div>

実装は以下の通りです。(Main.java)

package src;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;

public class Main {

	static final String expNow = "//div[@class='st-company']/dl/dd[@class='stc-now']";
	static final String expOpen = "//div[@class='st-top_price_detail']/dl[@class='stc-part1']/dd[@class='stc-opening']";
	static final String expHigh = "//div[@class='st-top_price_detail']/dl[@class='stc-part1']/dd[@class='stc-high']";
	static final String expLow = "//div[@class='st-top_price_detail']/dl[@class='stc-part1']/dd[@class='stc-low']";

	/**
	 * 引数に銘柄コードを入力してください。
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			URL url = new URL("http://www.nikkei.com/markets/company/index.aspx?scode="+ args[0]);
			URLConnection con = url.openConnection();
			Tidy tidy = new Tidy();
			tidy.setShowWarnings(false);
			tidy.setQuiet(true);
			Document doc = tidy.parseDOM(con.getInputStream(), null);
			XPathFactory xpf = XPathFactory.newInstance();
			XPath xpath = xpf.newXPath();
			String now = (String) xpath.evaluate(expNow, doc, XPathConstants.STRING);
			String open = (String) xpath.evaluate(expOpen, doc, XPathConstants.STRING);
			String high = (String) xpath.evaluate(expHigh, doc, XPathConstants.STRING);
			String low = (String) xpath.evaluate(expLow, doc, XPathConstants.STRING);
			System.out.println("now  : " + now);
			System.out.println("open : " + open);
			System.out.println("high : " + high);
			System.out.println("low  : " + low);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
	}
}

引数に指定したコードの各種値を取得します。expNow, expOpen, expHigh, expLowであらわされるXPath表現さえ覚えてしまえば、使いこなせるはず。

About of XPath Expression

W3に規定されていますので、ご参照いただければと思います。XML Path Language (XPath)

2012/6/21追記
FirefoxのアドオンにXPathを簡単に見れるのがあったので、追記しておきます。
XPath Checker

[Android]PhoneGap×Eclipseでサンプルをつくる

サンプルプロジェクトを作ってみる

PhoneGap Fanというサイトにサンプルアプリの作成手順がのっているのでその手順に従って作成してみようと思います。Xcodeで作成したい場合はこちらのページを参照してください。
まず、Eclipseを起動し、Androidプロジェクトをつくっていきます。

APIレベルを適当に決めます。

PhoneGapのライブラリをプロジェクトに追加する

まず、phonegap-1.2.0.jarを追加していきます。phonegap-1.2.0.jarが格納してあるディレクトリは「Android/」です。
次に、wwwディレクトリをassets下に作成して、phonegap-1.2.0.jsを追加します。phonegap-1.2.0.jsが格納してあるディレクトリは「Android/」です。
そして、以前Xcodeで作成したときと同様のhtmlファイルを配置しておきます。

jarファイルはビルドパスを通しておきます。phonegap-1.2.0.jarを選択して、右クリック > ビルドパス > ビルドパスに追加。

Android Manifestにパーミッションの追加

パーミッションの追加をします。おそらく、ライブラリ側に以下のパーミッションにアクセスするような実装が入ってしまうので、作ろうとしているアプリが、例えばカメラにアクセスするかしないかに関わらず、ライブラリの動作条件として以下のパーミッションを追加してあげる必要があるのでしょう。

	<supports-screens
		android:largeScreens="true"
		android:normalScreens="true"
		android:smallScreens="true"
		android:resizeable="true"
		android:anyDensity="true" />
	<uses-permission android:name="android.permission.CAMERA" />
	<uses-permission android:name="android.permission.VIBRATE" />
	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
	<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
	<uses-permission android:name="android.permission.INTERNET" />
	<uses-permission android:name="android.permission.RECEIVE_SMS" />
	<uses-permission android:name="android.permission.RECORD_AUDIO" />
	<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
	<uses-permission android:name="android.permission.READ_CONTACTS" />
	<uses-permission android:name="android.permission.WRITE_CONTACTS" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Activity.javaにindex.htmlを読み込ませる

AndroidのアプリケーションはApplicationという単位とActivityという大きな二つの単位があり、Activityとは一画面に相当します。単一の画面を持つアプリケーションを作成しようと思った場合はActivityというライブラリクラスを継承したクラスファイルを生成することになると思いますが、PhoneGapアプリケーションではDroidGapというクラスをActivityの代わりにスーパークラスにします。(結局はDroidGapはActivityのサブクラスですが、PhoneGap特有の処理を行ってくれるラッパー的なイメージですね。)
そして、レイアウトファイルを読み込む処理のところでassets下のindex.htmlを読み込ませる実装を書いて、Activity側の準備は環境です。

package com.yusuke.phonegap;

import android.os.Bundle;

import com.phonegap.DroidGap;

public class PhoneGapSampleActivity extends DroidGap {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.loadUrl("file:///android_asset/www/index.html");
    }
}

動かしてみる

起動!と思いきや、エラーで起動せず。。。

03-14 23:44:52.978: W/System.err(450): ERROR: plugin.xml is missing.  Add res/xml/plugins.xml to your project.

まだ、何か設定が足りなさそうなのでダウンロードしてきたファイルの中にplugins.xmlを発見。(Android/xml/plugins.xml)
これを指定通りに「res/xml」下におき、再度起動。

ばっちりです。Xcodeで作成したときのhtmlファイルでAndroid と iPhoneで同じ挙動を行わせることができました。
相互リンクを残しておきます。
[Mac]PhoneGap×Xcode4.2.1でサンプルをつくる
以前も書きましたが、これで開発効率のUPが見込めますね。プロダクションとしてこの技術を利用しているのはどれくらいなのだろうとちょっと気になりますが、非常に興味深い技術です。

[Android]Facemash的なアプリ

動機

なにかを作ってみたかった。「Facemash」的な。

成果物

■サーバーサイドモジュール
→ランキング機能を実装するために必要でした。クライアントアプリオンリーだと相当楽なのですが。
■FacebookSDKを使ったAndroid用クライアントアプリ

できること

Hot or Not、ランキング機能、履歴機能、お気に入り機能、推薦機能、アプリ内からブラウザにてログインしてメッセージ送信。
→可愛い女の子への最短ルート。となるはず。

問題点

登録されているユーザから無作為にクライアントに送信されるのですが、ユーザのメンテナンスが手動。。。
→自分の友達なら推薦できる機能をつけて、一応対応。
サーバの監視設定が皆無なので、トラブったときに検知できない。

キャプチャー

投票画面

ランキング画面

履歴画面

設定画面

リリース予定日

3月末にAndroidマーケットに登録する予定。

展望

Objective-Cを勉強中。iPhoneで同じものを実装してみたい。

[Android]ライブラリープロジェクトを作成して、外部プロジェクトから参照する方法

ライブラリープロジェクトを作成するわけ

アプリケーションを複数作成すると、この処理って以前のプロジェクトでも書いたよな、ということがよくあります。アプリケーション開発では業務(アプリケーションの内容)にとらわれない共通の処理が存在するので、そこを切り出してライブラリープロジェクトとして管理・メンテナンスしていったほうが効率がよいのだと思います。

ライブラリープロジェクトを作成する

ライブラリープロジェクトの属性を持たせるためには特にプロジェクトの作成の方法を気をつける必要はありません。ただ、プロジェクトのプロパティーに以下を追加してください。
プロジェクト直下のproject.propertiesに以下の一行を追加

android.library=true

ライブラリープロジェクトを参照する

ライブラリープロジェクトをライブラリープロジェクトとは別のプロジェクトから参照する方法です。
①プロジェクトを右クリック>ビルドパス>プロジェクトタブを選択し、ビルド・パス上に必要なプロジェクトとして選択します
※ライブラリープロジェクトのコードだけを参照する場合は①のみの設定でOKなはず。リソースファイルも参照したい場合はさらに②の手順を行います。
②プロジェクト直下のproject.propertiesに以下の一行を追加
android.library.reference.1=${フレームワークへのパス}