Android実行時にダウンロードしてJavaライブラリを使用するアプリケーションを作成する方法はありますか?
以下に例を示します。
アプリケーションが入力値に応じていくつかの計算を行う必要があると想像してください。アプリケーションはこれらの入力値を要求し、必要なClasse
sまたはMethod
sが利用可能かどうかを確認します。
そうでない場合、サーバーに接続し、必要なライブラリをダウンロードし、実行時にロードして、リフレクション技術を使用して必要なメソッドを呼び出します。実装は、ライブラリをダウンロードするユーザーなどのさまざまな基準に応じて変更される可能性があります。
申し訳ありませんが、私は遅れており、質問はすでに受け入れられていますが、yes、外部ライブラリをダウンロードして実行できます。ここに私がやった方法があります:
これが実現可能かどうか疑問に思っていたので、次のクラスを作成しました。
_package org.shlublu.Android.sandbox;
import Android.util.Log;
public class MyClass {
public MyClass() {
Log.d(MyClass.class.getName(), "MyClass: constructor called.");
}
public void doSomething() {
Log.d(MyClass.class.getName(), "MyClass: doSomething() called.");
}
}
_
そして、デバイスのSDカードに_/sdcard/shlublu.jar
_として保存したDEXファイルにパッケージ化しました。
次に、EclipseプロジェクトからMyClass
を削除してクリーンアップした後、以下の「愚かなプログラム」を作成しました。
_public class Main extends Activity {
@SuppressWarnings("unchecked")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
final String libPath = Environment.getExternalStorageDirectory() + "/shlublu.jar";
final File tmpDir = getDir("dex", 0);
final DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
final Class<Object> classToLoad = (Class<Object>) classloader.loadClass("org.shlublu.Android.sandbox.MyClass");
final Object myInstance = classToLoad.newInstance();
final Method doSomething = classToLoad.getMethod("doSomething");
doSomething.invoke(myInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
_
基本的にクラスMyClass
をそのようにロードします:
DexClassLoader
を作成します
クラスを使用して、MyClass
を_"/sdcard/shlublu.jar"
_から抽出します
このクラスをアプリケーションの_"dex"
_プライベートディレクトリ(電話の内部ストレージ)に保存します。
次に、MyClass
のインスタンスを作成し、作成されたインスタンスでdoSomething()
を呼び出します。
そしてそれは動作します... LogCatのMyClass
で定義されたトレースが表示されます:
エミュレーター2.1と物理的なHTC携帯電話(Android 2.2で、ルート化されていない)の両方で試してみました。
これは、アプリケーションがダウンロードして実行する外部DEXファイルを作成できることを意味します。ここでは難しい方法(madeいObject
キャスト、Method.invoke()
ugい呼び出し...)が行われましたが、Interface
sで遊んで何かをきれいにする必要があります。
ワオ。私は最初に驚いた。 SecurityException
を期待していました。
より多くの調査に役立ついくつかの事実:
Shlubluのアンサーは本当にいいです。いくつかの小さなことは初心者にも役立ちます:
ライブラリプロジェクトマニフェストで、次のことを確認してください:<application Android:icon="@drawable/icon" Android:label="@string/app_name"> <activity Android:name=".NotExecutable" Android:label="@string/app_name"> </activity> </application>
( ".NotExecutable"は予約語ではありません。ここに何かを入れなければなりませんでした)
.dexファイルを作成するには、ライブラリプロジェクトをAndroid application(コンパイル用))として実行し、プロジェクトのbinフォルダーから.apkファイルを探します。
その他の手順は、Shlubluの説明と同じです。
.DEXファイルを電話の外部メモリ(SDカードなど)に保存している場合(推奨されません!同じアクセス許可を持つアプリは、クラスを簡単に上書きしてコードインジェクション攻撃を実行できます)外部メモリを読み取るためのアプリの許可。この場合にスローされる例外は、誤解を招く「ClassNotFound」です。マニフェストに次のようなものを入れてください(最新バージョンについては、Googleにご相談ください)。
<manifest ...>
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"
Android:maxSdkVersion="18" />
...
</manifest>
Javaコードを動的にロードすることでこれを達成できるかどうかはわかりません。おそらく、Java動的にダウンロードおよび更新できるスクリプト。
確かに、それは可能です。インストールされていないapkはホストによって呼び出すことができますAndroid application.generally、resolve resource and activity's lifecircle、then、can can load jar or apk can.detail、please my open source research on github : https://github.com/singwhatiwanna/dynamic-load-apk/blob/master/README-en.md
また、DexClassLoaderとリフレクションが必要です。今、いくつかの重要なコードを見てください:
/**
* Load a apk. Before start a plugin Activity, we should do this first.<br/>
* NOTE : will only be called by Host apk.
* @param dexPath
*/
public DLPluginPackage loadApk(String dexPath) {
// when loadApk is called by Host apk, we assume that plugin is invoked by Host.
mFrom = DLConstants.FROM_EXTERNAL;
PackageInfo packageInfo = mContext.getPackageManager().
getPackageArchiveInfo(dexPath, PackageManager.GET_ACTIVITIES);
if (packageInfo == null)
return null;
final String packageName = packageInfo.packageName;
DLPluginPackage pluginPackage = mPackagesHolder.get(packageName);
if (pluginPackage == null) {
DexClassLoader dexClassLoader = createDexClassLoader(dexPath);
AssetManager assetManager = createAssetManager(dexPath);
Resources resources = createResources(assetManager);
pluginPackage = new DLPluginPackage(packageName, dexPath, dexClassLoader, assetManager,
resources, packageInfo);
mPackagesHolder.put(packageName, pluginPackage);
}
return pluginPackage;
}
あなたの要求は、冒頭で述べたオープンソースプロジェクトの機能の一部にすぎません。
技術的には機能するはずですが、Googleのルールはどうですか? From:play.google.com/intl/en-GB/about/developer-content-policy-pr int
Google Playを介して配信されるアプリは、Google Playの更新メカニズム以外の方法を使用して、それ自体を変更、置換、または更新することはできません。同様に、アプリはGoogle Play以外のソースから実行可能コード(dex、JAR、.soファイルなど)をダウンロードできません。この制限は、仮想マシンで実行され、Android API(WebViewまたはブラウザのJavaScriptなど)へのアクセスが制限されているコードには適用されません。
@Shlubluの答えは正しいと思いますが、いくつかの重要なポイントを強調したいだけです。
外部jarからUIをロードするには、fragmentを使用できます。フラグメントのインスタンスを作成し、アクティビティに埋め込みます。ただし、フラグメントが以下に示すようにUIを動的に作成することを確認してください。
public class MyFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup
container, @Nullable Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
LinearLayout layout = new LinearLayout(getActivity());
layout.setLayoutParams(new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
Button button = new Button(getActivity());
button.setText("Invoke Host method");
layout.addView(button, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
return layout;
}
}