apkにファイルを同梱して展開場所を指定する方法

1,821 views
Skip to first unread message

たろサ

unread,
Oct 6, 2010, 12:31:28 PM10/6/10
to android-g...@googlegroups.com
 こんにちは、たろサです。

 すいません、Androidもjavaも初心者でわからないので教えてください。

 自作したプログラムを公開してみたいのですが、作ったものがスクリプト言語なので、
スクリプトのサンプルをapkに同梱して、SDカードの指定フォルダに展開するようにした
いのですが、こういうことはできないのでしょうか。

 また、既にSDカードの指定フォルダに同名のスクリプトファイルがあれば、上書きしな
いようにしたいのですが、そのような指定は難しいのでしょうか。

 できるのであれば、教えてください。よろしくお願いします。

 できないのであれば、アプリ側でこういう処理も全て作り込むしかないのでしょうか・・。

--
山本三七男 (Minao Yamamoto) ---------------- ハンドル:たろサ -----
E-Mail: taro...@gmail.com

CLERK

unread,
Oct 6, 2010, 1:36:40 PM10/6/10
to 日本Androidの会
こんばんは、CLERKです。

> スクリプトのサンプルをapkに同梱して、SDカードの指定フォルダに展開するようにした
> いのですが、こういうことはできないのでしょうか。

画像などのリソース以外は「(Android プロジェクト)/assets」 以下に置くことで
APKに内包され、アプリケーションからアクセス可能となります。

assets 以下のファイルに対しては「getResources().getAssets().open()」で InputStream
が取得できます。これを利用してSDカードにファイルをコピーするコードを書くことで
実現できます。

この時、SDカードが存在しているか「Environment.getExternalStorageState()」で状態
をチェックし、「Environment.getExternalStorageDirectory()」でSDカードのルートディ
レクトリのパスを取得し、ファイルパスを作る手順を踏めば端末毎の違いを吸収できま
す。

>  また、既にSDカードの指定フォルダに同名のスクリプトファイルがあれば、上書きしな
> いようにしたいのですが、そのような指定は難しいのでしょうか。

こちらは、コピー処理の条件として「File.exists()」を利用しファイルが存在しているか
チェックをする事で可能です。
> E-Mail: taros...@gmail.com

たろサ

unread,
Oct 6, 2010, 11:21:47 PM10/6/10
to android-g...@googlegroups.com
 CLERKさん、こんにちは。

 非常に丁寧な説明で助かります。ありがとうございます。

 結論として、apkのインストール側の機能としてはSDカードにインテリジェントに展開
する機能は無いということですね。

 SDカードへのインストールはアプリ側で全て作りこむ必要があるというわけですね。
 了解しました。

 ありがとうございます。時間を見つけてアプリ側にインストール処理を作りこもうと思
います。

E-Mail: taro...@gmail.com

たろサ

unread,
Oct 7, 2010, 10:42:47 AM10/7/10
to android-g...@googlegroups.com
 たろサです。

 自力でasset以下に置いたファイルをsdcardにコピーする処理を書いているのですが、
エラーで止まります。何が原因なのでしょうか。
 エラーは「The application Luarida(...) has stopped unexpectedly. Please try
again.」です。
 
 下記がプログラムの抜粋です。(psSDCardDriveには"/sdcard"が入っています)

//asset/luarida/以下のファイルを、/sdcard/luarida/以下にコピーします
try {
AssetManager as = getResources().getAssets();
//assets/luarida/以下にあるファイル名を読み込みます
String[] luaridafiles = as.list(folder);
int n;
int DEFAULT_BUFFER_SIZE = 1024 * 4;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
//全てのファイルを/sdcard/luarida/以下にコピーします
for(int i=0; i<luaridafiles.length; i++ ){
InputStream is = as.open(folder+"/"+luaridafiles[i]);
String toFile = psSDCardDrive + "/" + folder + "/" + luaridafiles[i];
FileOutputStream output = openFileOutput( toFile,
Context.MODE_WORLD_WRITEABLE);
n = 0;
while (-1 != (n = is.read(buffer))) {
output.write(buffer, 0, n);
}
output.close();
is.close();
}
as.close();
} catch (IOException e) {
e.printStackTrace();
}

 下記の処理で落ちています。try-catchにも引っかからないです。
FileOutputStream output = openFileOutput(toFile,Context.MODE_WORLD_WRITEABLE);

 何が原因か分からないです。
 Manifestには、下記を追記しています。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 sdcardに対して、openFileOutputができないのでしょうか・・・?

 わかる方、教えてください。

(2010/10/07 2:36), CLERK wrote:

E-Mail: taro...@gmail.com

Yuki Anzai

unread,
Oct 7, 2010, 10:57:51 AM10/7/10
to android-g...@googlegroups.com
たろサさん

openFileOutput はアプリケーションデータ領域に
 書き出すときのメソッド(/data/data/[package name]/files/
 に書き出したいときに簡単にできるようにしたもの)なので、
 SDカードに書き出すときには使えません。
 普通に

File dstFile = new File(toFile);
 OutputStream output = new FileOutputStream(dstFile);

 とかでどうでしょう?

 ちなみに、 
 http://developer.android.com/reference/android/content/Context.html#openFileOutput%28java.lang.String,%20int%29
 には引数のファイル名にパスセパレータを入れてはいけないとあります。


---
あんざいゆき
anzai...@gmail.com
twitter : yanzm

たろサ

unread,
Oct 7, 2010, 1:04:13 PM10/7/10
to android-g...@googlegroups.com
 あんざいゆきさん、

 助言、ありがとうございます。

>  普通に
> File dstFile = new File(toFile);
>  OutputStream output = new FileOutputStream(dstFile);

 すいません。javaを始めたばかりで、何が'普通'なのか全然わかっていなかったりしま
す。前回のメールの後、上のようなやり方があることを発見して、組み込んで動かしてい
ました。
 無事、SDカードにかけるようになりました。ところがSDカードに書き込むと、SDに書き
込みを行ったときにだけ、別のところでエラーが発生するようになりました。

 下記がプログラムの抜粋です。

//asset/luarida/以下のファイルを、/sdcard/luarida/以下にコピーします
try {
AssetManager as = getResources().getAssets();

String[] luaridafiles;
luaridafiles = as.list(folder);
//assets/luarida/以下にあるファイル名を読み込みます


int n;
int DEFAULT_BUFFER_SIZE = 1024 * 4;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

for(int i=0; i<luaridafiles.length; i++ ){
InputStream is = as.open(folder+"/"+luaridafiles[i]);
String toFile = psSDCardDrive + "/" + folder + "/" + luaridafiles[i];

File outfile = new File(toFile);
OutputStream output = new FileOutputStream(outfile);


n = 0;
while (-1 != (n = is.read(buffer))) {
output.write(buffer,0,n);
}

output.flush();


output.close();
is.close();
}
as.close();
} catch (IOException e) {
e.printStackTrace();
}

ここは、思い通りに動いたのですが、他でエラーが発生します。このエラーに数時間
ずっと悩んでいました。全くエラーの原因の検討が付きません。

 エラー内容は「The application Luarida(...) has stopped unexpectedly. Please
try again.」です。

 どこで発生するかというと、この処理はonCreate()のところで行っているのですが、SD
書き込みが終わった後に、
//SurfaceViewを登録
setContentView(new LuaridaSurfaceView(this,this));

 このような処理をしています。デバッガで追いかけると、LuaridaSurfaceViewのクラス
の処理も無事終わり、setContentView(new LuaridaSurfaceView(this,this));のところに
みどりのカーソルが戻ってきて、そして、F5を押したときに落ちます。Logにもコンソー
ルにも何もエラーは出ておらず、デバッガの画面では、
「スレッド[<3>] main」(中断中(例外 RuntimeException))
ActivityThreadperformLaunchActivityThread$ActivityRecord, Intent)行2401
  .
.
.
ソースが見つかりませんでした。」
と出ています。

 実際問題、SDカードには書き込まれているので、このエラーでプログラムが終了して
も、次回起動させたときには、SDカードに既にファイルが存在するので、SDカードへの書
き込みが発生せず、このエラーは二度と出てきません。このアプリを初めて使う一回目だ
けエラーで落ちる感じです。

 ちなみに、フォルダを作る処理(下記)まで、動かして、ファイルをSDカードに書き込む
処理をコメントアウトして動作させた場合は、落ちませんでした。

File SDfolder = new File(psSDCardDrive + "/" + folder);
if( SDfolder.exists()){ return( true ); }
if (!SDfolder.mkdir()){
System.out.println( psSDCardDrive + "/" + folder +"/ の作成に失敗しました");
return(false);
}
/*
SDカードへの書き込み処理
*/
return(true);

 なので、落ちる原因はSDカードへの書き込みにあると思われるのですが、原因の検討が
全く付きません。

 これが原因ではないかな。と想像のつく方はいらっしゃいませんでしょうか。

E-Mail: taro...@gmail.com

たろサ

unread,
Oct 7, 2010, 1:20:58 PM10/7/10
to android-g...@googlegroups.com
 たろサです。

 いっそのこと、SDカードの書き込み処理後の処理を全てコメントアウトして動かしてみ
ました。この処理以外全てコメントアウトしています。

 中身は無いですか、onStart()、onResume()が走って、その後、落ちました。デバッガ
には、
「スレッド[<3>] main」(中断中(例外 Resources$NotFoundException))
Resources.loadXmlResourceParser(int,String)行:1877
.
.
.
クラスファイル・エディター

ソースが見つかりませんでした。」
と出ていまして、何かのソースのようなものが表示されています。

 んー、何だろう。

Akio Kondo

unread,
Oct 7, 2010, 1:40:53 PM10/7/10
to android-g...@googlegroups.com

こんどうです

logcatのログをみてみてださい
大概そこを見れば原因がわかります

2010/10/08 2:21 "たろサ" <taro...@gmail.com>:
> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。
>

たろサ

unread,
Oct 7, 2010, 2:19:42 PM10/7/10
to android-g...@googlegroups.com
 こんどうさん、こんにちは。

 logcatのログは一生懸命見ていますが、まだまだ、初心者なので見方が足りないのかも
知れません。

 logcatはこんな感じです。breakポイントを置かずにエラーまで言った場合です。
-----------
10-07 18:03:02.357: DEBUG/dalvikvm(30): GC freed 2 objects / 48 bytes in 395ms
10-07 18:03:02.367: INFO/System.out(257): Debugger has connected
10-07 18:03:02.367: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:02.567: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:02.776: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:02.976: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:03.180: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:03.383: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:03.587: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:03.790: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:03.992: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:04.195: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:04.398: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:04.600: INFO/System.out(257): waiting for debugger to settle...
10-07 18:03:04.803: INFO/System.out(257): debugger has settled (1320)
10-07 18:03:05.146: INFO/onCreate(257): 1
10-07 18:03:05.357: INFO/onCreate(257): 2
10-07 18:03:05.357: INFO/onStart(257): 1
10-07 18:03:05.357: INFO/onStart(257): 2
10-07 18:03:05.357: INFO/onResume(257): 1
10-07 18:03:05.357: INFO/onResume(257): 2
-----------
onCreate()の先頭に、Log.i("onCreate","1");と書いています。抜けるときに、
Log.i("onCreate","2");と書いています。この間に、SDカードへの書き込み処理がありま
す。それだけてす。
 そして、onStart()、onResume()にも、Log.i(メソッド名,"1");Log.i(メソッド
名,"2");が書いています。処理は特に書いていないです。
 ちなみに、onPause()、onStop()、onDestroy()にも、log.iを書いていますが、そこは
通っていないようです。
 下記が、onCreate()を抜ける直前のLog.i("onCreate","2");にbreakポイントを入れ
て、とめたあと、F8で続行してエラーになったときのLogcatです。timeoutはbreakしたせ
いだと思われます。
-----------
10-07 18:13:16.710: INFO/System.out(291): waiting for debugger to settle...
10-07 18:13:16.913: INFO/System.out(291): waiting for debugger to settle...
10-07 18:13:17.116: INFO/System.out(291): waiting for debugger to settle...
10-07 18:13:17.319: INFO/System.out(291): debugger has settled (1482)
10-07 18:13:17.755: INFO/onCreate(291): 1
10-07 18:13:23.871: WARN/ActivityManager(52): Launch timeout has expired, giving
up wake lock!
10-07 18:13:24.327: WARN/ActivityManager(52): Activity idle timeout for
HistoryRecord{439202a0 com.momoonga.luarida/.LuaridaActivity}
10-07 18:13:29.227: INFO/onCreate(291): 2
10-07 18:13:29.227: INFO/onStart(291): 1
10-07 18:13:29.227: INFO/onStart(291): 2
10-07 18:13:29.227: INFO/onResume(291): 1
10-07 18:13:29.227: INFO/onResume(291): 2
10-07 18:13:29.507: DEBUG/dalvikvm(96): GC freed 209 objects / 11072 bytes in 178ms
----------

 AndroidもJavaも難しいなぁ・・・。


(2010/10/08 2:40), Akio Kondo wrote:
> こんどうです
>
> logcatのログをみてみてださい
> 大概そこを見れば原因がわかります
>

> 2010/10/08 2:21 "たろサ" <taro...@gmail.com <mailto:taro...@gmail.com>>:

> >>> anzai...@gmail.com <mailto:anzai...@gmail.com>
> >>> twitter : yanzm
> >>>
> >>>
> >>>
> >>>
> >>>>  たろサです。
> >>>>
> >>>>  自力でasset以下に置いたファイルをsdcardにコピーする処理を書いているので

> <mailto:taros...@gmail.com>> wrote:
> >>>>>
> >>>>>>  こんにちは、たろサです。
> >>>>>>
> >>>>>>  すいません、Androidもjavaも初心者でわからないので教えてください。
> >>>>>>
> >>>>>>  自作したプログラムを公開してみたいのですが、作ったものがスクリプト言語
> なので、
> >>>>>> スクリプトのサンプルをapkに同梱して、SDカードの指定フォルダに展開するよ
> うにした
> >>>>>> いのですが、こういうことはできないのでしょうか。
> >>>>>>
> >>>>>>  また、既にSDカードの指定フォルダに同名のスクリプトファイルがあれば、上
> 書きしな
> >>>>>> いようにしたいのですが、そのような指定は難しいのでしょうか。
> >>>>>>
> >>>>>>  できるのであれば、教えてください。よろしくお願いします。
> >>>>>>
> >>>>>>  できないのであれば、アプリ側でこういう処理も全て作り込むしかないので
> しょうか・・。
> >>>>>>
> >>>>>> --
> >>>>>> 山本三七男 (Minao Yamamoto) ---------------- ハンドル:たろサ -----

> >>>>>> E-Mail: taros...@gmail.com <mailto:taros...@gmail.com>


> >>>>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>
> >>
> >
> >
> > --
> > 山本三七男 (Minao Yamamoto) ---------------- ハンドル:たろサ -----

> > E-Mail: taro...@gmail.com <mailto:taro...@gmail.com>


> >
> > --
> > このメールは Google グループのグループ「日本Androidの会」の登録者に送られてい
> ます。
> > このグループに投稿するには、android-g...@googlegroups.com

> <mailto:android-g...@googlegroups.com> にメールを送信してください。
> > このグループから退会するには、android-group-
> japan+un...@googlegroups.com
> <mailto:android-group-japan%2Bunsu...@googlegroups.com> にメールを送信してく
> ださい。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=ja から
> このグループにアクセスしてください。

たろサ

unread,
Oct 7, 2010, 2:42:30 PM10/7/10
to android-g...@googlegroups.com
 たろサです。

 いろいろ、試して、わかってきました。
 先ず、onCreate()のところで、setContentView()もコメントアウトしてしまったらエ
ラーになるようです。

 次に、setContentView()が走った後に、SD書き込み処理を走らせたときは、エラーにな
らないようです。

 SD書き込みを行った後で、setContentView()が走ると、そこでエラーになるようです。

 なんでかな?

宮山

unread,
Oct 7, 2010, 9:23:50 PM10/7/10
to 日本Androidの会
宮山です。

SDカードへの書き込みはAndroidManifest.xmlに権限を入れないといけませんが
記述されているか確認されてはどうでしょうか?

以下の記述が必要です。

<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

記述済みでしたらすいません。

以上、よろしくお願いいたします。
> >> 2010/10/08 2:21 "たろサ"<taros...@gmail.com<mailto:taros...@gmail.com>>:
> ...
>
> もっと読む ≫

Akio Kondo

unread,
Oct 7, 2010, 9:56:49 PM10/7/10
to android-g...@googlegroups.com
こんどうです

おそらくSD書き込み処理の中にfindViewByIdがあるのではないかと思うのですが、
setContentViewよりも前にfindViewByIdを使うとうまくいきません。
まず使用するレイアウトやViewを決定してからでないと
findViewByIdでViewを取得することができないからです。

2010/10/8 たろサ <taro...@gmail.com>:

たろサ

unread,
Oct 7, 2010, 11:01:59 PM10/7/10
to android-g...@googlegroups.com
 たろサです。

 動作しましたので報告します。

 原因はSD書き込みの処理(下記)のところで、 'as.close();'しているところでした。
AssetManagerをクローズしてはいけないようです。リファレンスを見ると、このclose()
はAssetManagerをcloseさせるもののようですね。setContentView()処理でAssetManager
を使って処理しているところがあるのですね。たぶん。

//asset/luarida/以下のファイルを、/sdcard/luarida/以下にコピーします
try {
AssetManager as = getResources().getAssets();
String[] luaridafiles;
luaridafiles = as.list(folder);
//assets/luarida/以下にあるファイル名を読み込みます
int n;
int DEFAULT_BUFFER_SIZE = 1024 * 4;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

//全てのファイルを/sdcard/luarida/以下にコピーします
for(int i=0; i<luaridafiles.length; i++ ){
InputStream is = as.open(folder+"/"+luaridafiles[i]);
String toFile = psSDCardDrive + "/" + folder + "/" + luaridafiles[i];

File outfile = new File(toFile);
OutputStream output = new FileOutputStream(outfile);
n = 0;
while (-1 != (n = is.read(buffer))) {
output.write(buffer,0,n);
}
output.flush();
output.close();
is.close();
}

//as.close();
} catch (IOException e) {
e.printStackTrace();
}

 こんどうさんの助言「logcatのログをみてみてださい。大概そこを見れば原因がわかり
ます」これが大事でした。

 私は、まず、logcatの見方をわかっていませんでした。デバッグで落ちた(止まった)と
きにはデバッガがエラーをトラップしているので、logcatには何も出てこないのですね。
デバッガがエラーをトラップして実行が止まったにも関わらず、続行させたらエラーがど
ばっとlogcatに吐かれました。
 このエラーの元を見たら、「AssetManagerを閉じているよ」と書いていました。原因究
明にものの1分も掛かりませんでした。

 「logcatに出るエラーを見るためには、F8で続行させる」が今回の私の教訓です。

 いろいろ、ありがとうございました。 

Reply all
Reply to author
Forward
0 new messages