플러그식 플러그인화 실현 (1)
앞말
로 분리한다. 이 모듈은
와
를 포함하고 각 모듈은 하나apk
(모듈화된 각 모듈은 lib
파일), 최종 포장 시 apk
와 apk
를 분리하여 포장한다.apk
65535
;
의
는 관리하기 어렵다. 플러그인이 설치되지 않았기 때문에 상하문이 없기 때문에 생명주기와 관련된 모든 방법은 직접 호출할 수 없다.android 9.0
에 @hide
의 주석이 있어서 이 방법은 개발자에게 보이지 않는다.2. 사고방식 분석 실현
새
library
를 만들어서 apk
와 apk
를 모두 이것library
에 의존하게 하고 apk
과 apk
에서 모두 이 기준을 실현해야 하며 apk
의 생명주기가 관리된다. public interface PayInterfaceActivity {
/**
* activity context
*
*/
void attach(Activity proxyActivity);
/**
*
*/
void onCreate(Bundle savedInstanceState);
void onStart();
void onResume();
void onPause();
void onStop();
void onRestart();
void onDestroy();
void onSaveInstanceState(Bundle outState);
boolean onTouchEvent(MotionEvent event);
void onBackPressed();
}
숙주 apk 코드 구현
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mBtn_load;
private Button mBtn_jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PluginManager.getInstance().setContext(this);
mBtn_load = findViewById(R.id.btn_load);
mBtn_jump = findViewById(R.id.btn_jump);
setListener();
}
private void setListener() {
mBtn_load.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// ,
loadPlugin();
}
});
mBtn_jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// activity activity
// activity ProxyActivity,proxyActivity activity
Intent intent = new Intent(MainActivity.this, ProxyActivity.class);
//activities[0] launcher activity
intent.putExtra("className", PluginManager.getInstance().getPackageInfo().activities[0].name);
startActivity(intent);
}
});
}
private void loadPlugin() {
// app ,
File pluginDir = getDir("plugin", Context.MODE_PRIVATE);
String name = "pluginb.apk";
String filePath = new File(pluginDir, name).getAbsolutePath();
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
InputStream is = null;
OutputStream os = null;
try {
File file1 = new File(Environment.getExternalStorageDirectory(), name);
Log.i(TAG, "load: file1 = " + file1.getAbsolutePath());
is = new FileInputStream(file1);
os = new FileOutputStream(file);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
if (new File(filePath).exists()) {
Toast.makeText(this, " ", Toast.LENGTH_SHORT).show();
}
// ,
PluginManager.getInstance().loadPath(this);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
플러그인 관리 클래스
/**
* description: , ,
*/
public class PluginManager {
private Context mContext;
private PluginManager() {
}
private static final PluginManager instance = new PluginManager();
public static PluginManager getInstance() {
return instance;
}
private PackageInfo mPackageInfo;
private DexClassLoader mDexClassLoader;
private Resources mResources;
//
public void loadPath(Context context) {
// activity
//
String pluginbPath = getPluginPath(context);
// apk activity
PackageManager manager = context.getPackageManager();
mPackageInfo = manager.getPackageArchiveInfo(pluginbPath, PackageManager.GET_ACTIVITIES);
File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);
/**
* DexClassLoader mResources
* dexPath: apk
* optimizedDirectory: ,
* librarySearchPath: ,
* ClassLoader
*/
mDexClassLoader = new DexClassLoader(pluginbPath, dexOutFile.getAbsolutePath(), null, context.getClassLoader());
try {
// @hide ,
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, pluginbPath);
mResources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
} catch (Exception e) {
e.printStackTrace();
}
}
private String getPluginPath(Context context) {
File pluginDir = context.getDir("plugin", Context.MODE_PRIVATE);
String name = "pluginb.apk";
return new File(pluginDir, name).getAbsolutePath();
}
public DexClassLoader getDexClassLoader() {
return mDexClassLoader;
}
public Resources getResources() {
return mResources;
}
public PackageInfo getPackageInfo() {
return mPackageInfo;
}
public void setContext(Context context) {
mContext = context;
}
}
숙주에서 플러그인의activity를 불러옵니다
/**
* description:ProxyActivity , activity ,
* activity, ,xxxx.class, assert, resource
* , intent class
*/
public class ProxyActivity extends Activity {
// activity
private String className;
private static final String TAG = "ProxyActivity";
private PayInterfaceActivity mPayInterfaceActivity;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
className = getIntent().getStringExtra("className");
Log.i(TAG, "onCreate: className = " + className);
// class (why?), Class , app ( ?),
// classLoader class
try {
//className--->Class-- -->className activity ---> activity onCreate() activity
Class> activityClass = getClassLoader().loadClass(className);
// activity , apk , mainActivity
Constructor> constructor = activityClass.getConstructor();
// instance activity, activity , onCreate()
// onCreate() ,
Object instance = constructor.newInstance();
// instance apk MainActivity, apk Activity PayInterfaceActivity ,
// TODO: 2018/4/27 java.lang.ClassCastException: com.wvbx.alipayplugin.MainActivity cannot be cast to com.wvbx.paystandard.PayInterfaceActivity
mPayInterfaceActivity = (PayInterfaceActivity) instance;
mPayInterfaceActivity.attach(this);
// activity activity , bundle
Bundle bundle = new Bundle();
mPayInterfaceActivity.onCreate(bundle);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void startActivity(Intent intent) {
// activity activity
String className = intent.getStringExtra("className");
Intent intent1 = new Intent(this, ProxyActivity.class);
intent1.putExtra("className", className);
super.startActivity(intent1);
}
// ProxyActivity activity,
// ProxyActivity activity
// PayInterfaceActivity ,
@Override
protected void onStart() {
super.onStart();
mPayInterfaceActivity.onStart();
}
@Override
protected void onPause() {
super.onPause();
mPayInterfaceActivity.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mPayInterfaceActivity.onDestroy();
}
// classLoader,
@Override
public ClassLoader getClassLoader() {
return PluginManager.getInstance().getDexClassLoader();
}
@Override
public Resources getResources() {
return PluginManager.getInstance().getResources();
}
}
플러그인 activity의 기본 클래스
/**
* description:
* apk , , ,
* activity ,
*/
public class BaseActivity extends Activity implements PayInterfaceActivity {
// activity
protected Activity that;
@Override
public void attach(Activity proxyActivity) {
this.that = proxyActivity;
}
@Override
public T findViewById(int id) {
if (that != null) {
return that.findViewById(id);
} else {
return super.findViewById(id);
}
}
@Override
public void setContentView(int layoutResID) {
if (that != null) {
that.setContentView(layoutResID);
} else {
super.setContentView(layoutResID);
}
}
@Override
public Intent getIntent() {
if (that != null) {
return that.getIntent();
} else {
return super.getIntent();
}
}
@Override
public ClassLoader getClassLoader() {
if (that != null) {
return that.getClassLoader();
} else {
return super.getClassLoader();
}
}
@NonNull
@Override
public LayoutInflater getLayoutInflater() {
if (that != null) {
return that.getLayoutInflater();
} else {
return super.getLayoutInflater();
}
}
@Override
public ApplicationInfo getApplicationInfo() {
if (that != null) {
return that.getApplicationInfo();
} else {
return super.getApplicationInfo();
}
}
@Override
public Window getWindow() {
if (that != null) {
return that.getWindow();
} else {
return super.getWindow();
}
}
@Override
public void startActivity(Intent intent) {
// activity , activity , proxyActivity1 proxyActivity2
//proxyActivity-->className
Intent i = new Intent();
// activity standard
i.putExtra("className",intent.getComponent().getClassName());
// that proxyActivity
that.startActivity(i);
}
@Override
public void setContentView(View view) {
if (that != null) {
that.setContentView(view);
} else {
super.setContentView(view);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
}
@Override
public void onStart() {
}
@Override
public void onResume() {
}
@Override
public void onPause() {
}
@Override
public void onRestart() {
}
@Override
public void onStop() {
}
@Override
public void onDestroy() {
}
@Override
public void onSaveInstanceState(Bundle outState) {
}
}
계승
BaseActivity
의 자activitypublic class MainActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// xml onclick , ,
findViewById(R.id.main).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// MainActivity.this,
Toast.makeText(that, " ", Toast.LENGTH_SHORT).show();
that.startActivity(new Intent(that, SecondActivity.class));
}
});
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.