Androidのアプリ開発関連のブログ

ライブラリ・プロジェクトの作成

antでAndroidアプリを作る際、コード共通化のためにアプリを一部分離してライブラリ化したり、オープンソースのライブラリを組み込む方法。


android create lib-project -n プロジェクト名 -t ターゲット -p パス -k パッケージ名
アプリのプロジェクトを作る場合は、android create projecですが、 android create lib-projectにするだけですね。
-tで指定するターゲットは、android list targets」で確認できるid
lib-projectを作成した場合はsrc以下に何もできないので、srcに.javaファイルをぶち込むだけ。


アプリ側で
ライブラリを使用する場合は、アプリ側のproject.propertiesに、
android.library.reference.1=相対パス
と1行。
2個以上のライブラリを使用する場合は、android.library.reference.2


普通にantでビルドする場合はjavacのsourceオプションが1.5になって、オープンソースのライブラリ使ったりする場合にエラーが出るかもしれないが、
lib-project側のant.propertiesに、
java.source=7
java.target=7
とかするとsourceオプションが指定できる。

また1ヶ月空いてしまったが・・・

結局また1ヶ月何も作らなかったが、再開する。
定番だが、QRリーダー作ってみようかと思ってたわけで、先月調べたところSurfaceViewというアニメーション等の更新が必要なものを表示するViewがあり、カメラのプレビューにはそれ使う。
というわけで、まずはSurfaceViewにカメラの表示。


AndroidManifest.xml
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>
この2行を、<manifest>の下(<application>の前に書いた)に書いとく。
<uses-permission>でアプリがカメラを使えるようにして、<uses-feature>を書いておくとアプリ配信時にカメラ無し端末はGooglePlayに表示されなくなる。


APIリファレンスだとカメラはandroid.hardware.Cameraが非推薦でandroid.hardware.camera2を使うように書かれているが、camera2はAPIレベル21。
API 21はAndroid 5.0かな?流石に要件厳しすぎるんでandroid.hardware.Cameraの方使うことに。


MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.hardware.Camera;

public class MainActivity extends Activity{
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final Camera camera;
        if(Camera.getNumberOfCameras()==1){
            camera=Camera.open();
        }else{
            Camera.CameraInfo ci=new Camera.CameraInfo();
            Camera.getCameraInfo(0,ci);
            if(ci.facing==ci.CAMERA_FACING_BACK){
                camera=Camera.open(0);
            }else{
                camera=Camera.open(1);
            }
        }
        SurfaceView sv=(SurfaceView)findViewById(R.id.sv);
        sv.getHolder().addCallback(new SurfaceHolder.Callback(){
            public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
           
            }
            public void surfaceCreated(SurfaceHolder holder){
                try{
                    camera.setPreviewDisplay(holder);
                    camera.startPreview();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            public void surfaceDestroyed(SurfaceHolder holder){
           
            }
        });
    }
}

40行ほどになってしまったが、半分は背面カメラの判別コード。
最初のお試しにはカメラの判別はしなくていいと思うんで、もっと簡単。

layoutファイルでSurfaceViewを定義。
コード中でidでSurfaceViewを取得して、getHolder()でSurfaceHolderを取得。
addCallbackでコールバックを設定。
addCallbackの引数はSurfaceHolder.Callback一つで、SurfaceHolder.Callbackはイベントリスナ的なやつかな?surfaceChanged、surfaceCreated、surfaceDestroyedの3つを定義する。
今回はお試しなんで、surfaceCreatedだけ定義した。これがSurfaceView作成時に1回だけ呼びだされて、内容変更時にsurfaceChanged、破棄時にsurfaceDestroyedが呼び出される感じかな。

Camera.open()で1番目のカメラが起動、カメラ番号を引数に渡すこともできCamera.open(1)だと2番目になるのかな?
Camera.getNumberOfCameras()で端末のカメラ数を取得できる。

SurfaceView作成時に呼び出されるsurfaceCreatedでカメラのプレビューを開始してSurfaceViewに描画する。
起動中のカメラのsetPreviewDisplay(holder)でSurfaceHolderを設定。
startPreview()するだけ。
tryで例外処理する必要があるけど、簡単だね。


今回はカメラが複数ある場合は背面カメラを使い、一つの場合はそれを起動。としたかったわけだが、
Callback内(サブクラス内)でカメラの取得が必要そうなんで、final修飾子つけた。
finalの時はその行で初期化しないとダメなもんだと思ってたが、確実に定義されるなら次以降のif文等で定義することもできるんだね。
対象カメラの判別をしてから定義する必要があるんで、final変数をif文内で初期化にした。
カメラが複数の場合はforで全カメラを判別すべきな気もするが、for内でfinal変数の初期化はできない?やりかたわからん。
端末にカメラが3個以上付いているというのはありえないよね?2個あるなら1番か2番のカメラのどちらかが確実に背面だと思うんで、forじゃなくてif文にした。

カメラの前背面の判別は、Camera.CameraInfo()で判別できるんだが、なんかわかりにくい。
static void Camera.getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo)
↑これ
Cameraのstaticメソッドを使うんだが、直接CameraInfoを返してくれる仕様ならわかりやすいが、voidなんだよね。
空のCameraInfoを自分で作成してgetCameraInfoの引数として渡す。そうすると渡したCameraInfoで情報を得ることができるって仕様。
背面なら、取得したCameraInfoのfacingが、Camera.CameraInfo.CAMERA_FACING_BACKになる。
前面なら、Camera.CameraInfo.CAMERA_FACING_FRONT。



そんなわけで、カメラを扱うのはできた。
QRの解析にはZxingって定番ぽいライブラリ使うつもりだが、プレビュー中のカメラから自動で定期的にビットマップを取得してZxingで処理する感じだね。
やる気出せばとりあえずのものは1日でできると思うが、やる気が出るか・・・

QRコードリーダーを作ろうかと・・・

2ヶ月何も作ってなかったが、ネタもないので定番どころになってしまうが、QRコードリーダーを作ろうかと。

このブログでアプリへのリンクにQRコードを表示しているが、それのQRコード生成処理が自作なのだが、
QRコードは仕様かなり難解で、カメラでの撮影だと角度とかの補正もあるから自力で全部作るのは難しいと思うんだが、
数あるAndroidのQRリーダーアプリではZxingってライブラリが使われているみたい。

QRリーダーアプリいくつか使ってみると、どれも同じ処理してるのわかりますが、
  • QR以外のバーコードもまとめて解析しちゃうので、読み取りにくいQRだと誤判別しちゃう。
  • テキストの種別を表示するアプリはあるのだが、詳細なQRの種別を表示できるアプリは無い。
以前QRコード生成処理を作った際にAndroidのリーダーアプリを解析に使用したが、そこら不便だったんで、可能ならその辺考えたしようにしたい。
って感じかな。
ただ、Zxingのリファレンス見た感じ、DataMatrixって規格のバーコードは詳細取得できそうなんだが、QRコードはできないかも・・・
海外だとQRコードよりもDataMatrixって規格の方が主流なのかな?
カメラ以外に画像ファイルからQR解析できるような機能も付けたいかな。


まず、カメラの画面をアプリに表示するのにSurfaceViewってのを使うぽい。
SurfaceViewは、アニメーション等のUIスレッドと分ける必要がある物を描画するのに使うViewらしい。
Zxingにはビットマップデータを渡すと解析できるぽい。
ので、
まずは、SurfaceViewにカメラを描画するところからかな。

FTPクライアント配信した

制作していたFTPクライアントは、ちょっとサボってて遅れたが昨日完成して配信した。



先週の時点で一通り作り終わって、翻訳、アイコン等画像作成、AdMob設置で終わりと思ってたんだが、
完成したつもりの状態でテストしてみて、登録済みサーバーの編集機能と、リモートファイルの外部アプリでの編集機能が実装されてないことに気づいたんで実装した。


これで4個目のアプリをGoogle Playで配信したが、今後もどんどんなにか作って配信していきたい。が、ネタがないw

FTP関連のアプリを2個続けて、SFTPにも対応させたから、SSH端末アプリなんかやりたいところではあるが、
topとかviみたいな画面全体奪うようなコマンドの実装ってどうなってるんだろうか?
そこらできればやりたいし、非対応でもとりあえずのSSH端末としてはありか?

まあ、なにか適当に作ろうと思うが、広告設置が向かなそうなのは他アプリへの誘導用にしか役立たないからあまりやらない方針。

一通り機能できたぽい

制作中のFTPクライアントは、一通り機能できた感じ。

サーバー登録は前のテキストエディターをほぼ完全流用でいいと思ったが、前はgetがファイルパスを返して戻ってから読み込みだったが、
今回のは読み込みというものが無く、getするときに転送だから、秘密鍵取得のために読み込み処理入れる必要があった。


後は英語化をしようと思うのと、
アイコンとかGoogle Playで必要な画像の準備と、AdMobの設置かな。

今週前半に完成させられる見込みだったが、週末までかかってしまった。