Unity compiled Android's principle parsing and apk packaging analysis

Source: Internet
Author: User

Http://www.cnblogs.com/qcloud1001/p/6650023.html

Recently, because I wanted to invoke the interface of Android's activity in the script component of scene, we needed to figure out the actual correspondence between scene and activity, and studied some of the principles that unity calls Android.

This article focuses on the relationship between scene and activity, and where is the difference between Unity Pack apk and Android Studio pack apk? When you find this difference, how can you use it?

Tools to use in this article:

    • Android Anti-compilation tool--apktool
    • Android Studio's own anti-compilation feature
What is the entrance to the program that compiles unity's scene into apk,apk?
    1. Build a new Unity project, create a scene, and package the Unity Project compilation as an APK.
    2. Against the compiled apk, use Apktool to decompile: Apktool D unitytest.apk
    3. The resulting androidmanifest files are as follows:
<?xml version="1.0" encoding="Utf-8" standalone="No"?><ManifestXmlns:android="Http://schemas.android.com/apk/res/android"android:installlocation="Preferexternal"Package="Com.xfiction.p1"Platformbuildversioncode="25"Platformbuildversionname="7.1.1" ><Supports-screensandroid:anydensity="True"android:largescreens="True"android:normalscreens="True"android:smallscreens="True"android:xlargescreens="True"/><ApplicationAndroid:banner="@drawable/app_banner"android:debuggable="False"android:icon="@drawable/app_icon"Android:isgame="True"Android:label="@string/app_name"Android:theme="@style/unitythemeselector" ><Activityandroid:configchanges="Locale|fontscale|keyboard|keyboardhidden|mcc|mnc|navigation|orientation|screenlayout|screensize| Smallestscreensize|touchscreen|uimode "Android:label="@string/app_name"Android:launchmode="Singletask"Android:name="Com.unity3d.player.UnityPlayerActivity"android:screenorientation="Fullsensor" ><Intent-filter><ActionAndroid:name="Android.intent.action.MAIN"/><CategoryAndroid:name="Android.intent.category.LAUNCHER"/><CategoryAndroid:name="Android.intent.category.LEANBACK_LAUNCHER"/></Intent-filter><Meta-dataAndroid:name="Unityplayer. Unityactivity "Android:value="True"/></Activity></Application><Uses-featureandroid:glesversion= "0x00020000"/> <uses-feature Span class= "hljs-attr" >android:name= "Android.hardware.touchscreen" android:required= "false"/> << Span class= "Hljs-name" >uses-feature android:name= " Android.hardware.touchscreen.multitouch "android:required=" False "/> <uses-feature android:name = "android.hardware.touchscreen.multitouch.distinct" android: Required= "false"/></manifest                 

By the Androidmanifest file, the system still exists the main activity, the name is com.unity3d.player.UnityPlayerActivity.

In the words, compile only the scene Unity project, packaged into Android APK, Will take com.unity3d.player.UnityPlayerActivity as the main program entrance, then the question comes, how does scene load display to this unityplayeractivity?

Second, unityplayeractivity How to load scene in unity?

2.1 unityplayeractivity

This is going to start with the unityplayeractivity source, Android Engineering uses unityplayeractivity to rely on Unity's Android plug-in Classes.jar (located in the Unity installation directory, can be found with everything software lookup), to decompile it to get unityplayeract Ivity part of the source code:

PublicClassunityplayeractivity extends  Activity {protected unityplayer Munityplayer; protected void oncreate This.requestwindowfeature (1); super.oncreate (VAR1); this.getwindow (). SetFormat (2); this.munityplayer = new Unityplayer ( this); this.setcontentview (this.munityplayer); this.munityplayer.requestfocus ();}}         

Although confusing and seemingly laborious, it can be seen from Code This.setcontentview (This.munityplayer) that the final interface display needs to be dependent on unityplayer instances.
In addition, because Google also made a Unity VR SDK, and unityplayeractivity corresponding to the class, is googleunityactivity, which is also analyzed below.

2.2 Starting from Googleunityactivity.java and analyzing

Googleunityactivity is a Google-launched VR SDK that is used to implement unity activity classes, and Google queries its source discovery:
1. Googleunityactivity.java the actual layout file Activity_main.xml

<?xml version="1.0" encoding="Utf-8"?><framelayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= " Match_parent "> <framelayout android : Id= "@+id/android_view_container" android:layout_width= "match_parent" android:layout_height= " Match_parent "android:background=" @android: Color/transparent " /></FRAMELAYOUT>      

There is no specific content in the layout file, only one framelayout layout is included.

2. Focus on the OnCreate function of googleunityactivity:

PublicClassGoogleunityactivityExtendsActivityImplementsActivitycompat.Onrequestpermissionsresultcallback {protected void oncreatesuper.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); Setcontentview (r.id.activity_main.xml) Munityplayer = new UnityPlayer (this); if (Munityplayer.getsettings (). Getboolean ( "Hide_status_bar ", true)) {GetWindow (). SetFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } ((ViewGroup) Findviewbyid (Android. r.id.content). AddView (Munityplayer.getview (), 0); Munityplayer.requestfocus ();}}  

Munityplayer as Framelayoutview is added to the view collection for display, note that the ID found here is android. R.id.content. According to the official explanation of this ID:
Android. R.id.content gives you the root element of a view, without has to know its actual name/type/id. Check out Get root view from current activity

Thus, googleunityactivity's implementation principle is to create an empty frame layout that contains only framelayout, The view in the Unityplayer is then loaded into the googleunityactivity via AddView to display.

Looks similar to unityplayeractivity, both of which are involved in the Unityplayer.

What kind of a 2.3.UnityPlayer is it?

To decompile the Classes.jar package, get unityplayer part of the code:

PublicClassUnityplayerExtendsFramelayoutImplementsCom.Unity3d.Player.A.APublicstatic Activity currentactivity =NullPublicUnityplayer(Contextwrapper var1) {Super (VAR1);if (var1instanceof activity) {currentactivity = (activity) var1;}}Public ViewGetView() {ReturnThis }PublicStaticNativevoidUnitysendmessage(String var0, String var1, string var2);PrivateFinalNativeBooleanNativerender();Publicvoid oncameraframe(final com.unity3d.player.a var1, final byte[] var2) { final int var3 = Var1.a (); final Size VAR4 = var1.b (); THIS.A (new unityplayer.c (byte)0) {public  final void a() {Unityplayer.  This.nativevideoframecallback (Var3, Var2, Var4.width, var4.height); var1.a (VAR2); } }); }}

From the code you can find:

    1. Unityplayer is actually inherited from Framelayout;
    2. And comes with a currentactivity member variable, in the constructor, directly into the activity of the relevant parameters;
    3. The framelayout is returned directly in the GetView function;
    4. Googleunityactivity passes its context to unityplayer through the Unityplayer constructor, and assigns it to its member variable currentactivity.

Because the Unityplayer class is confusing, the core function of rendering is also encapsulated in the native code, and there is only one simple conjecture about scene switching to Unityplayer as Framelayout: by invoking the Android GL rendering engine, Render at the native layer and sync to framelayout on unityplayeractivity.

Iii. How to display scene in custom activity

From the above research, we can see that if we want to show the scene in fixed activity, we need to deal with the Countview and Unityplayer of the oncreate part of activity. The simplest approach is to write a class that inherits directly from the unityplayeractivity or googleunityactivity and writes the required unity call to Android in the class.
The scene will be loaded in a particular activity, and Unity C # can get to the activity and invoke the function in it by acquiring the currentactivity variable.

Iv. issues needing attention in Unity Android plugin
    1. Android Studio project contains multiple module dependencies, you need to copy the corresponding module compiled plug-in Plugins/android/lib directory.
    2. In the first step, you can directly delete the packaged AAR library directory, especially if the Android plugin with Unity Classesjar, otherwise it will compile the error.
    3. When more than one module compiles, note the manifest Lablel related settings, the other is Build.gradle minsdkversion information. Otherwise, an error manifest merger failure will occur.
    4. About Unity's Android manifest file merge:
      Unity writes a scene,android studio to write an AAR package containing the main activity, which is placed in the Plugins/android directory. After compiling the apk out with unity, decompile his androidmanifest file, two main activity, which shows the activity with the scene by default.
      WORKAROUND: Unity's manifest file merge, put a manifest in the Plugins/android directory, will not merge manifest.
V. Structure of Unity Pack Android APK

As Unity develops Android, it is often designed to switch between Unity + visual and Android studio environments, and unity is often developed faster and more of the Android Java side of code writing and debugging.

In this case, is there a way to put Unity's compiled unity scene and C # related files into Android studio for packaging and debugging directly in Android Studio?

The principle of the method is very simple, by comparing the unity packaged apk, with the common Android apk file differences, find the Unity file storage directory, then corresponding to the Android Studio project directory, and finally through the Android Studio completes the packaging of the unity-related files.

First add the apk to the zip suffix, easy to compare with beyond compare:

    1. Discover just a assert/bin directory, under which you can see the unity-related DLL library
    2. Copy the file to the Src/main/assert directory of the Android studio project;
    3. When you debug in Android Studio, you can set up the AAR Library project as an app project so that you can compile the APK to run to your phone.
    4. Compile the project with Android Studio and discover that the Assert/bin directory was successfully packaged in.
    5. Direct APK install run, you can see the unity compiled with the package apk, is the same effect.

Conversely, if the Android project has been debugged, it will be compiled into the library mode directly, and after the build, the AAR libraries are generated and the AAR library is copied to the Plugins/android/lib directory. Note To delete the Assert/bin in the AAR library, because this directory is the one we previously copied from unity, and if not deleted, there will be a case of file conflicts in unity that results in duplicate packaging.

Android Studio is a library project that needs to be converted to app engineering, since it was copied to Android studio after the bin directory was packaged in unity.
This involves the conversion of the Android Studio library and the app by setting up the Build.gradle file to achieve:

    • App mode: Apply plugin: ' Com.android.application '
    • Library mode: Apply plugin: ' Com.android.library '

However, in setting these two modes, you need to pay attention to the ApplicationID "com.example.yin.myapplication" setting, if it is the library mode, you need to comment out directly.

If the Java part of Android is re-debugged, re-changing the app mode to library mode, build, and copy the generated AAR package to the Unity Android plugin directory, you can see the effect directly in unity.
Be sure to remember to delete the Assert/bin directory inside the AAR files packaged by Android Studio to prevent repeated packaging in unity.

Iv. Conclusion:
    1. Scene in Unity in Android, in fact, corresponds to the activity of the framelayout, each scene of the operation has its activity environment, through the currentactivity variable can be obtained.
    2. To implement a custom activity with the ability to load the scene directly, you need to inherit from unityplayeractivity or googleunityactivity, or directly customize the implementation of the Unityactivity class.
    3. Ways to improve the efficiency of Unity+android plugin project development:
      Copy the Assert/bin directory from the Unity packaged apk directly into the Src/main/assert directory of the Android Studio project and configure the Android project as app mode, directly on Android studio , the whole Unity+android plugin project is debugged.
      After debugging the Android studio, you need to modify the Build.gradle file, re-modify the app mode to library mode, compile the AAR package file, delete the original copy of the unity part, and put it into Unity's plugins/ Android/lib directory to use.

The last set of famous sayings: Log good, bug solved early

Unity compiled Android's principle parsing and apk packaging analysis

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.