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

複数ファイルの編集ができるように・・・

制作中のテキストエディターは、昨日BufferedReader.readLine()すると改行が消えちゃう件で検討してたが、
LFまたはCRが最初に出現するまでは1文字ずつ読み込んで、出現したところで改行コードの判別処理。
以降の行はreadLine()で読み込んで"\n"追加。
"\n"追加するとファイル末尾に改行が増えちゃうから対応した。

FTP部分はBufferedReaderの前にInputStreamReader通してたけど、
InputStreamReaderのコンストラクタ第二引数で文字コードの指定ができるんで、文字コード指定のリロード機能もつけた。
ローカルファイルの読み込み処理はFileReaderでやってたが、FileReaderのコンストラクタでは文字コードが指定できないんで、FileInputStreamを使うようにした。

InputStreamからのテキスト読み込み処理が25行くらいになったが、3箇所あってほぼ同じなんで、専用クラス作って分離をしようと思う。


ファイルの保存部分はまだ作ってないんだが、
アクションバーのアイコン部分のタッチで、タブUIのテキストエディタみたいに複数ファイルの編集ができるようにできないかと思ったんで、
そうするつもりで、ファイルの読み込み状態を複数保存するようにした。


あとの作業は上記の分も入れて、
  • ファイル読み込み処理の分離。
  • アイコン部分のタッチでファイル切り替え。
  • ファイル保存処理を作る。
  • 初回読み込み時の文字コード指定機能。
  • 文字コードと改行コードの保存前変換処理。
  • UIの調整、string.xmlの調整、AdMobつけたり。
それでテキストエディタとしては十分かなとは思うが、
当初予定してたHTMLファイル特化のモード実装とか、(無くてもいいかなと思い始めたw)
テキストの一部のハイライトってどうやるんだ?簡単なら実装したい。
って感じかな。

Apache Commonsは簡単だった

Javaでのプログラミングはなかなか捗らないが、Apache Commons使ってFTPは結構簡単だった。

FTPClient ftp=new FTPClient();
ftp.connect(host);
ftp.login(user,pass);
こんな感じで接続して、

ftp.changeWorkingDirectory(path);
で作業ディレクトリの変更。

ディレクトリのファイル一覧は、
ftp.listFiles()
でFTPFileの配列が取得できるから、
for(FTPFile f:ftp.listFiles()){

}
こんな感じでループ処理。
FTPFileのメソッドでファイル名やディレクトリかファイルかなどの情報が取得できる。
パーミッションも取得できるが、ログインユーザー名とファイルシステムのユーザー名が同じとは限らないから、パーミッションに関しては実際に読み書きしてみないとわからないね多分。

ファイルの読み込みは、
ftp.setFileType(ftp.BINARY_FILE_TYPE);
でバイナリモードに設定して、
ftp.retrieveFileStream(filename);
でInputStreamが取得できる。
FTPにはサーバーが対応していればアスキーモードが使えるるが、あれは改行コードが勝手に変換されて罠なんで使い道ない。

書き込みはまだやってないが、
ftp.storeFileStream(filename);
でOutputStream取得して書き込めばいいのかな?


FTPに関してはそんな感じなんだが、
InputStreamからBufferedReaderにしてreadLine()で読み込もうと思ってたんだが、
BufferedReader.readLine()って改行コードが含まれないんだね。
ファイルの読み込みはローカルファイルも処理作ったが、そっちもダメだな。

1文字ずつ読み込むか、java.nio.Bufferのサブクラス使ってやろうかなと検討してるところなんだが、
改行コードを取得して保存時に再変換したり、それのついでにUTF-8以外の文字コードに対応させるなら、InputStreamReader使うのがいいのかな?
Javaはほんと似たようなのがいっぱいあって困る・・・


ファイルの保存処理を作ったら、ローカルとFTPのファイル関連処理は終わりかな。
SFTPはganymed-ssh-2を使う予定だが、FTPと同じように作れば問題ないと思ってる。
Apache CommonsにはFTPじゃなくてFTPSClientもあるからFTPSも対応させようと思うが、サンプルコード見たら、
ftp=ftps;
みたいになってたから、
FTPClientとFTPSClientでメソッド等は同じなんだと思う。
初期化部分だけ変えれば同じ処理でできそう。


ネットワーク含めてファイル関連の処理が終わったら、UI系。
HTMLファイルはブラウザモードと、できればDOMインスペクタ的なモードも用意したいと思ってるんで、結構めんどいかも。

テキストハイライトは無い状態でとりあえず完成いいかなと思うんだが、
Google Playで配信されてるテキストエディタでハイライトのあるやつがあるようだが、どうやって実装するんだろ?
普通のEditTextで一部だけ文字色変えたりできるのか?

URLConnectionでFTPできない

制作中のテキストエディタにFTP機能実装させようとして、
FTPはAndroid APIのjava.net.URLConnectionで利用できると思ったんだが、なんか繋がらない・・・

エミュレーターだと標準じゃportが開かないからダメなのかな?
と、実機でやってみたが、同じ。
と思ったが、PASVモードはport開けなくて使えるよね。
URLConnectionはPASV非対応?

URLConnectionでのFTPについてググってみたが、実装例が全然出てこなく、Apache Commonsってので実装してることが多いみたい。
やっぱURLConnectionのFTPは限定的で実用できないような気がする・・・


というわけで、Apache Commons使う方向に・・・

Apache Commonsのソースダウンロードしてきて、
android create lib-project -n commons_net -t 5 -p lib/commons-net -k org.apache.commons.net
てな感じで、 ganymed-ssh-2を試した時と同じだが、lib-projectを作成。
作成したlib-projectのsrcにソースを置く。

アプリの方のproject.propertiesに、
android.library.reference.1=../lib/commons-net
と、相対パスでlib-projectのパスを書く。


とりあえずこれでimportしてビルドできた。
実際に使ってみるのは後ほど・・・

ファイルの保存はできた

SSHターミナルの方は中止して、テキストエディタの方を先に作ることにしたが、
ローカルの書き込み可能ディレクトリを選択して、そこにファイルを保存する処理は作れた。

AndroidManifest.xmlに、
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
を追加しないとアプリ領域以外は書き込み可にならないわけだね。
設定すると保存領域に書き込みできるグループにアプリが追加されるぽい。
これを設定すると、java.io.File.canWrite()で書き込み可が取得できる。

あとは、java.io.Fileとjava.io.FileWriter使って文字列の書き込みは簡単だった。


最終的に、FTPとSFTPは最低でも書き込みできるようにするんで、ネット系を実装するか、
先にローカルファイルの読み込みとか編集周りの実装をやるか・・・

一応レスポンスは取得できた

AsyncTaskLoaderでganymed-ssh-2でSSH接続して、一応レスポンスは取得できた。
でも、AsyncTaskLoaderで非同期で接続したままメインスレッドからコマンド送るいい方法がまだわからないのと、
ターミナルアプリを作ろうとすると、ただ結果が出力されるコマンドならいいが、「top」「vi」「nano」とか画面奪われるコマンドの実装方法がわからんな。
Google PlayにAndroid用SSHクライアントはいくつかあるっぽいが、実装してるのかな?

ganymed-ssh-2でのログインは、
conn.authenticateWithPassword(user,pass)
がパスワードログイン用で、引数は共にString渡せばいい。
公開鍵認証は、
conn.authenticateWithPublicKey(user,key,pass);
と、パスワードも渡さなきゃいけなく、
keyはFileを渡すかchar[]を渡すかどっちかで、Stringはダメらしい。
パスワードはnullでいいみたい。

切断時に切断待ちしないのかな?
連続ですぐに再接続しようとすると接続できない問題があった。
再度jschの方も試してこの問題あるか確認しようと思ったが、
やっぱjschのサンプルコード見ると、InputStreamが入力でOutputStreamが出力のように見える。
OutputStreamが出力だとファイルを経由させるとかしないと排他制御の仕方がわからん。
直接STDOUTに出力するならいいが、アプリ内で処理しようとなるとjschの仕様は難しいように思える。


まあ、今の時点ではターミナルアプリは良い感じに作れそうにない。
というわけなんで、パスワードと公開鍵の両方でログイン方法はわかったんで、ターミナルアプリはとりあえず中止にしてSFTPもできるようにするつもりのエディタアプリの方を制作再開するかな。
当初はローカルファイルからで。

後々通信も実装させるが、AsyncTaskLoaderよりもAsyncTaskにした方がいいかもしれん。