Android plug-in development-run the Service and androidapk that are not installed in the apk

Source: Internet
Author: User

Android plug-in development-run the Service and androidapk that are not installed in the apk
If you do not know what plug-in development is, you should first read this blog: Android plug-in development.

The previous blog mainly analyzed several difficulties in Android plug-in development from the overall perspective and the methods for dynamically loading the Activity and resources in the uninstalled apk. In fact, the general plug-in development is mainly to load an Activity and read some resource images. However, there are always special situations, such as loading services.

There are two ways to dynamically load a Service: one is to run the Service through C ++ in the form of NDK (I didn't try this method, only listen to friends in the Group); the other is what I use, the specific idea is the same as the method mentioned in the previous article to load the Activity, using the form of hosting, since the previous blog did not make it clear, here is a detailed description of how to load the Service in the plug-in through hosting.

The following are some of the things that every Android developer must know: An apk cannot be run directly if it is not installed. A java class file can be read through the classload class loader. An apk is actually a compressed package, which contains a. dex file, which is our code file. Then, we can clarify the basic idea: the apk cannot be run directly. The apk contains code files that can be read by classload.

There are two types of classload in Android: DexClassLoader and PathClassLoader. The latter can only load the apk under the/data/app directory, that is, the apk must be installed before it can be loaded. This is not what we want, so we use the former: DexClassLoader.

Public class CJClassLoader extends DexClassLoader {// create a plug-in loader set. Using a fixed loader for a fixed dex prevents errors caused by Simultaneous loading of one dex by multiple loaders. Private static final HashMap <String, CJClassLoader> pluginLoader = new HashMap <String, CJClassLoader> (); protected CJClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {super (dexPath, optimizedDirectory, libraryPath, parent);}/*** returns the loader corresponding to dexPath */public static CJClassLoader getClassLoader (String dexPath, Context cxt, ClassLoader parent) {CJClassLoader cjLoader = pluginLoader. get (dexPath); if (cjLoader = null) {// obtain the app startup path final String dexOutputPath = cxt. getDir ("dex", Context. MODE_PRIVATE ). getAbsolutePath (); cjLoader = new CJClassLoader (dexPath, dexOutputPath, null, parent); pluginLoader. put (dexPath, cjLoader);} return cjLoader ;}}

The above is just the beginning. Next we need to consider a problem. A Service has the oncreate-> onstart-> ondestroy lifecycle and some callback methods, these callback methods are normally used by the parent class (including has... a... link) or SDK management. When we load data through the class loader, there is no parent class that can be managed, in other words, we need to simulate the SDK to manage the callback function of the plug-in Service. The class to manage the plug-in Service is the hosting Institute mentioned earlier.

Here is an interface that I extract the callback method in the Service.

public interface I_CJService {    IBinder onBind(Intent intent);     void onCreate();     int onStartCommand(Intent intent, int flags, int startId);     void onDestroy();     void onConfigurationChanged(Configuration newConfig);     void onLowMemory();     void onTrimMemory(int level);     boolean onUnbind(Intent intent);     void onRebind(Intent intent);     void onTaskRemoved(Intent rootIntent);}

// A Managed class CJProxyService extends Service {// use the include relation protected I _CJService mPluginService; // plug-in Service object}

Here we use the include link instead of the Inheritance (or implementation of an interface) method,

This is because we need to override the methods in the Service, and these override methods all need to use the corresponding interface methods of the interface object.

public class CJProxyService extends Service{        @Override    public void onConfigurationChanged(Configuration newConfig) {        mPluginService.onConfigurationChanged(newConfig);        super.onConfigurationChanged(newConfig);    }     @Override    public void onLowMemory() {        mPluginService.onLowMemory();        super.onLowMemory();    }     @Override    @SuppressLint("NewApi")    public void onTrimMemory(int level) {        mPluginService.onTrimMemory(level);        super.onTrimMemory(level);    }     @Override    public boolean onUnbind(Intent intent) {        mPluginService.onUnbind(intent);        return super.onUnbind(intent);    }     @Override    public void onRebind(Intent intent) {        mPluginService.onRebind(intent);        super.onRebind(intent);    }}

As you can see, the hosting Service is actually a common Service class, but the hosting Service runs normally and the callback function is managed by the SDK, through the callback function of this Service, we call the corresponding callback method in the plug-in Service to indirectly manage the life cycle of the plug-in Service (here we can compare the relationship between Activity and Fragment)

So far, we can successfully call a plug-in Service. The following question is: where does the I _CJSrvice object come from? It's easy to load

Private void init (Intent itFromApp) {Object instance = null; try {Class <?> ServiceClass; if (CJConfig. DEF_STR.equals (mDexPath) {serviceClass = super. getClassLoader (). loadClass (mClass);} else {serviceClass = this. getClassLoader (). loadClass (mClass);} Constructor <?> ServiceConstructor = serviceClass. getConstructor (new Class [] {}); instance = serviceConstructor. newInstance (new Object [] {});} catch (Exception e) {} setRemoteService (instance); mPluginService. setProxy (this, mDexPath);}/*** retain a plug-in Service Object */protected void setRemoteService (Object service) {if (service instanceof I _CJService) {mPluginService = (I _CJService) service;} else {throw new ClassCastException ("plugin service must implements I _CJService ");}}

In this way, you can get an I _CJSrvice object mPluginService. If the problem persists, in this case, the onStart method in mPluginService also corresponds to the onStart in the plug-in, that is, the onStart of the parent class (here we do not know how to describe it), and we have said before, the class loaded by reflection does not have a parent class. If the @ Override method of the reflection object is forcibly called at this time, a null pointer is reported because the parent class cannot be found. The solution is to re-write each @ Override in the plug-in Service.

//....... Limited space, partially intercepting public abstract class CJService extends Service implements I _CJService {/*** that the Pointer Points to the Context of the current plug-in (because it is plug-in development, this pointer is definitely not usable) */protected Service that; // replace this pointer @ Override public IBinder onBind (Intent intent) {if (mFrom = CJConfig. FROM_PLUGIN) {return null;} else {return that. onBind (intent );}}}

We can see through the generation: we use an that object to replace the original this object, and then we only need to assign this that object to the managed this object in the hosting, that is, all that in the plug-in. xxx is equivalent to calling the hosting site this. xxx, then the purpose of dynamic replacement is achieved, so that we can successfully load a Service in the uninstalled plug-in apk.

For the code in this class and the complete Demo, you can follow: Android plug-in-type development framework CJFrameForAndroid

In android development, when an apk file is generated using software developed by Baidu Map API, it cannot be installed.

Can you debug and run the simulator? If the installation is not possible on the machine, use another installer or copy it to the SD card for installation. And the minimum value set for your sdk version. If the value is higher than the current version of the device, installation fails. The above is my guess. I will paste your LOG and check it.

After android development programs are installed on mobile phones

Java. lang. RuntimeException: Unable to instantiate activity ComponentInfo {com. example. calculator/com. example. calculator. MainActivity}: java. lang. NullPointerException

A null pointer exception occurred during Activity initialization. It is estimated that the id of your button in the xml file is inconsistent with the id in the Activity, and the corresponding button cannot be found.

You can comment out the code segment that initializes the button and sets listener for the button, and try deploying it again!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.