Skip to content

Commit 029b33f

Browse files
author
zhangming
committed
init
1 parent 7858fb8 commit 029b33f

75 files changed

Lines changed: 1381 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/build.gradle

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 23
5+
buildToolsVersion "23.0.2"
6+
7+
defaultConfig {
8+
applicationId "com.simen.dynamicclassloader"
9+
minSdkVersion 15
10+
targetSdkVersion 23
11+
versionCode 1
12+
versionName "1.0"
13+
}
14+
buildTypes {
15+
release {
16+
minifyEnabled false
17+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18+
}
19+
}
20+
}
21+
22+
dependencies {
23+
compile fileTree(dir: 'libs', include: ['*.jar'])
24+
testCompile 'junit:junit:4.12'
25+
compile 'com.android.support:appcompat-v7:23.3.0'
26+
compile 'com.android.support:design:23.3.0'
27+
}

app/proguard-rules.pro

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Add project specific ProGuard rules here.
2+
# By default, the flags in this file are appended to flags specified
3+
# in /Users/ABC/Library/Android/sdk/tools/proguard/proguard-android.txt
4+
# You can edit the include path and order by changing the proguardFiles
5+
# directive in build.gradle.
6+
#
7+
# For more details, see
8+
# http://developer.android.com/guide/developing/tools/proguard.html
9+
10+
# Add any project specific keep options here:
11+
12+
# If your project uses WebView with JS, uncomment the following
13+
# and specify the fully qualified class name to the JavaScript interface
14+
# class:
15+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16+
# public *;
17+
#}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.simen.dynamicclassloader;
2+
3+
import android.app.Application;
4+
import android.test.ApplicationTestCase;
5+
6+
/**
7+
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
8+
*/
9+
public class ApplicationTest extends ApplicationTestCase<Application> {
10+
public ApplicationTest() {
11+
super(Application.class);
12+
}
13+
}

app/src/main/AndroidManifest.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="com.simen.dynamicclassloader"
3+
xmlns:android="http://schemas.android.com/apk/res/android">
4+
5+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
6+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
7+
<application
8+
android:allowBackup="true"
9+
android:icon="@mipmap/ic_launcher"
10+
android:label="@string/app_name"
11+
android:supportsRtl="true"
12+
android:theme="@style/AppTheme">
13+
<activity
14+
android:name=".MainActivity"
15+
android:label="@string/app_name"
16+
android:theme="@style/AppTheme.NoActionBar">
17+
<intent-filter>
18+
<action android:name="android.intent.action.MAIN"/>
19+
20+
<category android:name="android.intent.category.LAUNCHER"/>
21+
</intent-filter>
22+
</activity>
23+
<!-- <activity
24+
android:name="dynamicclassloader.loadingapk.MainActivity"
25+
android:label="@string/app_name"
26+
android:theme="@style/AppTheme.NoActionBar">
27+
</activity>-->
28+
</application>
29+
30+
</manifest>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.loading;
2+
3+
4+
import android.content.Context;
5+
6+
/**
7+
* Created by zhangming on 16/6/5.
8+
*/
9+
public interface Loading {
10+
public String getName();
11+
12+
public boolean startLoading(String msg);
13+
14+
public boolean startLoading(Context context, String msg);
15+
16+
String getMessage(Context context, String msg);
17+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.loading;
2+
3+
4+
import android.content.Context;
5+
6+
/**
7+
* Created by zhangming on 16/6/5.
8+
*/
9+
public class MainLoader implements Loading {
10+
@Override
11+
public String getName() {
12+
return "i am the baseloader(app)";
13+
}
14+
15+
@Override
16+
public boolean startLoading(String msg) {
17+
System.out.println(msg);
18+
return true;
19+
}
20+
21+
@Override
22+
public boolean startLoading(Context context, String msg) {
23+
System.out.println(msg);
24+
return true;
25+
}
26+
27+
@Override
28+
public String getMessage(Context context, String msg) {
29+
return "baseapp:" + msg;
30+
}
31+
}
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package com.simen.dynamicclassloader;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.content.pm.PackageManager;
6+
import android.content.res.Resources;
7+
import android.os.Bundle;
8+
import android.os.Environment;
9+
import android.support.design.widget.FloatingActionButton;
10+
import android.support.design.widget.Snackbar;
11+
import android.util.Log;
12+
import android.view.View;
13+
import android.support.design.widget.NavigationView;
14+
import android.support.v4.view.GravityCompat;
15+
import android.support.v4.widget.DrawerLayout;
16+
import android.support.v7.app.ActionBarDrawerToggle;
17+
import android.support.v7.app.AppCompatActivity;
18+
import android.support.v7.widget.Toolbar;
19+
import android.view.Menu;
20+
import android.view.MenuItem;
21+
import android.widget.Toast;
22+
23+
import com.loading.Loading;
24+
25+
import java.io.File;
26+
import java.lang.reflect.Constructor;
27+
import java.lang.reflect.Method;
28+
29+
import dalvik.system.BaseDexClassLoader;
30+
import dalvik.system.DexClassLoader;
31+
32+
/**
33+
* support jar,apk,aar,dex
34+
*/
35+
public class MainActivity extends AppCompatActivity
36+
implements NavigationView.OnNavigationItemSelectedListener {
37+
38+
@Override
39+
protected void onCreate(Bundle savedInstanceState) {
40+
super.onCreate(savedInstanceState);
41+
setContentView(R.layout.activity_main);
42+
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
43+
setSupportActionBar(toolbar);
44+
45+
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
46+
fab.setOnClickListener(new View.OnClickListener() {
47+
@Override
48+
public void onClick(View view) {
49+
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
50+
.setAction("Action", null).show();
51+
}
52+
});
53+
54+
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
55+
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
56+
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
57+
drawer.setDrawerListener(toggle);
58+
toggle.syncState();
59+
60+
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
61+
navigationView.setNavigationItemSelectedListener(this);
62+
}
63+
64+
@Override
65+
public void onBackPressed() {
66+
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
67+
if (drawer.isDrawerOpen(GravityCompat.START)) {
68+
drawer.closeDrawer(GravityCompat.START);
69+
} else {
70+
super.onBackPressed();
71+
}
72+
}
73+
74+
@Override
75+
public boolean onCreateOptionsMenu(Menu menu) {
76+
// Inflate the menu; this adds items to the action bar if it is present.
77+
getMenuInflater().inflate(R.menu.main, menu);
78+
return true;
79+
}
80+
81+
@Override
82+
public boolean onOptionsItemSelected(MenuItem item) {
83+
// Handle action bar item clicks here. The action bar will
84+
// automatically handle clicks on the Home/Up button, so long
85+
// as you specify a parent activity in AndroidManifest.xml.
86+
int id = item.getItemId();
87+
88+
//noinspection SimplifiableIfStatement
89+
if (id == R.id.action_settings) {
90+
return true;
91+
}
92+
93+
return super.onOptionsItemSelected(item);
94+
}
95+
96+
@SuppressWarnings("StatementWithEmptyBody")
97+
@Override
98+
public boolean onNavigationItemSelected(MenuItem item) {
99+
// Handle navigation view item clicks here.
100+
int id = item.getItemId();
101+
102+
if (id == R.id.nav_camera) {
103+
loadAndroidJar();
104+
} else if (id == R.id.nav_gallery) {
105+
loadUninstallApk();
106+
} else if (id == R.id.nav_slideshow) {
107+
loadInstallApk("dynamicclassloader.loadingapk");
108+
} else if (id == R.id.nav_manage) {
109+
loadDex();
110+
} else if (id == R.id.res_camera) {
111+
resAndroidJar();
112+
} else if (id == R.id.res_gallery) {
113+
resUninstallApk();
114+
} else if (id == R.id.res_slideshow) {
115+
resInstallApk("dynamicclassloader.loadingapk");
116+
} else if (id == R.id.res_manage) {
117+
resDex();
118+
}
119+
120+
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
121+
drawer.closeDrawer(GravityCompat.START);
122+
return true;
123+
}
124+
125+
126+
/**
127+
* @Title: loadUninstallApk
128+
* @Description: 动态加载未安装的apk
129+
*/
130+
private void loadUninstallApk() {
131+
String path = Environment.getExternalStorageDirectory() + File.separator;
132+
String filename = "loadingapk-debug.apk"; // 4.1以后不能够将optimizedDirectory设置到sd卡目录, 否则抛出异常.
133+
File optimizedDirectoryFile = getDir("dex", 0);
134+
DexClassLoader classLoader = new DexClassLoader(path + filename, optimizedDirectoryFile
135+
.getAbsolutePath(), null, getClassLoader());
136+
try { // 通过反射机制调用, 包名为com.example.loaduninstallapkdemo, 类名为UninstallApkActivity
137+
Class mLoadClass = classLoader.loadClass("com.loading.MainLoader");
138+
Constructor constructor = mLoadClass.getConstructor(new Class[]{});
139+
Object testClass = constructor.newInstance(new Object[]{});
140+
// 获取getName方法
141+
Method helloMethod = mLoadClass.getMethod("getName", new Class[]{});
142+
helloMethod.setAccessible(true);
143+
Object content = helloMethod.invoke(testClass, new Object[]{});
144+
Toast.makeText(MainActivity.this, content.toString(), Toast.LENGTH_LONG).show();
145+
} catch (Exception e) {
146+
e.printStackTrace();
147+
}
148+
}
149+
150+
private void loadUninstallApk(String msg) {
151+
String path = Environment.getExternalStorageDirectory() + File.separator;
152+
String filename = "loadingapk-debug.apk"; // 4.1以后不能够将optimizedDirectory设置到sd卡目录, 否则抛出异常.
153+
File optimizedDirectoryFile = getDir("dex", 0);
154+
DexClassLoader classLoader = new DexClassLoader(path + filename, optimizedDirectoryFile
155+
.getAbsolutePath(), null, getClassLoader());
156+
try { // 通过反射机制调用, 包名为com.loading, 类名为MainLoader
157+
Class mLoadClass = classLoader.loadClass("com.loading.MainLoader");
158+
Constructor constructor = mLoadClass.getConstructor(new Class[]{});
159+
Object testClass = constructor.newInstance(new Object[]{});
160+
// 获取startLoading方法
161+
Method helloMethod = mLoadClass.getMethod("getMessage", new Class[]{Context.class,
162+
String.class});
163+
helloMethod.setAccessible(true);
164+
//调用startLoading方法,并注入参数
165+
Object content = helloMethod.invoke(testClass, new Object[]{this, msg});
166+
Toast.makeText(MainActivity.this, content.toString(), Toast.LENGTH_LONG).show();
167+
} catch (Exception e) {
168+
e.printStackTrace();
169+
}
170+
}
171+
172+
private void resInstallApk(String packName) {
173+
174+
}
175+
176+
private void resUninstallApk() {
177+
178+
}
179+
180+
private void loadInstallApk(String pkgName) {
181+
try {
182+
Context context = createPackageContext(pkgName, Context.CONTEXT_IGNORE_SECURITY | Context
183+
.CONTEXT_INCLUDE_CODE);
184+
// // 获取动态加载得到的资源
185+
// Resources resources = context.getResources();
186+
// // 过去该apk中的字符串资源"app_name",并且toast出来,apk换肤的实现就是这种原理
187+
// String toast = resources.getString(resources.getIdentifier("app_name", "string", pkgName));
188+
// Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
189+
Class cls = context.getClassLoader().loadClass(pkgName + ".MainActivity");
190+
// 跳转到该Activity
191+
startActivity(new Intent(this, cls));
192+
} catch (ClassNotFoundException e) {
193+
e.printStackTrace();
194+
} catch (Resources.NotFoundException e) {
195+
e.printStackTrace();
196+
} catch (PackageManager.NameNotFoundException e) {
197+
e.printStackTrace();
198+
}
199+
}
200+
201+
/**
202+
* @Title: loadandroidJar/loadAndroidAar
203+
* @Description: 项目工程中必须定义接口, 而被引入的第三方jar包实现这些接口,然后进行动态加载。
204+
* 相当于第三方按照接口协议来开发, 使得第三方应用可以以插件的形式动态加载到应用平台中。
205+
*/
206+
private void loadAndroidJar() {
207+
final File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString()
208+
+ File.separator + "loadingandroidjar-debug.aar"); //jar also is supported
209+
210+
BaseDexClassLoader cl = new BaseDexClassLoader(Environment.getExternalStorageDirectory().toString(),
211+
optimizedDexOutputPath, optimizedDexOutputPath.getAbsolutePath(), getClassLoader());
212+
Class libProviderClazz = null;
213+
try {
214+
// 载入JarLoader类,并且通过反射构建JarLoader对象,然后调用getName方法
215+
libProviderClazz = cl.loadClass("com.loading.MainLoader");
216+
Loading loader = (Loading) libProviderClazz.newInstance();
217+
Toast.makeText(MainActivity.this, loader.getName(), Toast.LENGTH_SHORT).show();
218+
} catch (ClassNotFoundException e) {
219+
e.printStackTrace();
220+
} catch (InstantiationException e) {
221+
e.printStackTrace();
222+
} catch (IllegalAccessException e) {
223+
e.printStackTrace();
224+
}
225+
}
226+
227+
private void resAndroidJar() {
228+
229+
}
230+
231+
private void loadDex() {
232+
233+
}
234+
235+
private void resDex() {
236+
237+
}
238+
239+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportHeight="24.0"
5+
android:viewportWidth="24.0">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
9+
<path
10+
android:fillColor="#FF000000"
11+
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
12+
</vector>

0 commit comments

Comments
 (0)