There is an Android game made in Flash that was packaged using Adobe AIR, but it no longer works for Android versions above 7. I was wondering if it is possible to repackage this game using HARMAN's Adobe AIR?
I have downloaded HARMAN's Adobe AIR and attempted to repackage the application using the ADT package command. I used the application.xml
file that was present in the APK's assets/META-INF/AIR/
folder. However, this application uses extensions, and it appears that ADT expects ANE (AIR Native Extension) files, or is there some other way?
I couldn't find the ANE files online. But some Chinese hackers were able to repackage the app, working in Android 10, and the folder assets/META-INF/AIR/extensions
folder has suffered no changes in comparison with the original apk. The files in the folder lib/armeabi-v7a
were updated however, and include a new one called libX86Bridge.so
.
The extensions that the original app uses are:
So I have finally been able to repackage the APK, and it works on recent Android versions!
First, I opened the APK file with an archive manager (APK is a ZIP file), and then converted the classes.dex
file inside the APK to a JAR file, using the dex2jar tool. Inside the JAR file (which is also a ZIP file) are the compiled Java classes from the AIR Native Extensions that the app uses.
Then, inside the bin
directory of Adobe AIR by HARMAN I created a directory for each extension:
AIRSDK_Windows\bin
├── com.adobe.ane.social
├── com.milkmangames.extensions.AndroidIAB
├── com.chartboost.plugin.air
├── com.milkmangames.extensions.CoreMobile
├── com.jirbo.airadc.AirAdColony
├── com.milkmangames.extensions.GoViral
The unpacked extension ANEs could be found inside the APK, in the path /assets/META-INF/AIR/extensions/
.
For each extension, added catalog.xml
and library.swf
into a ZIP file, and renamed the ZIP extension to SWC (e.g.: com.adobe.ane.social.swc
). Then, placed the SWC file inside the respective extension's directory.
Inside each extension's directory in the APK, there is a path META-INF/ANE/
where the file extension.xml
and other files can be found (e.g.: /assets/META-INF/AIR/extensions/com.adobe.ane.social/META-INF/ANE/
). I placed all the files inside these directories in the directories of the respective extensions that I created in the bin
directory. For the com.chartboost.plugin.air
extension, for example, this is what the directory structure looks like:
AIRSDK_Windows\bin
├── com.adobe.ane.social
├── com.milkmangames.extensions.AndroidIAB
├── com.chartboost.plugin.air
│ ├── com.chartboost.plugin.air.swc
│ ├── extension.xml
│ ├── Android-ARM
├── com.milkmangames.extensions.CoreMobile
├── com.jirbo.airadc.AirAdColony
├── com.milkmangames.extensions.GoViral
I opened the extension.xml
file, and these were its contents:
<extension xmlns="http://ns.adobe.com/air/extension/16.0">
<id>com.chartboost.plugin.air</id>
<versionNumber>5.5.0</versionNumber>
<platforms>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>libChartboostAir.jar</nativeLibrary>
<initializer>com.chartboost.plugin.air.ChartboostExtension</initializer>
<finalizer>com.chartboost.plugin.air.ChartboostExtension</finalizer>
</applicationDeployment>
</platform>
<platform name="iPhone-ARM">
<applicationDeployment>
<nativeLibrary>libChartboostAir.a</nativeLibrary>
<initializer>ChartboostExtInitializer</initializer>
<finalizer>ChartboostExtFinalizer</finalizer>
</applicationDeployment>
</platform>
<platform name="default">
<applicationDeployment/>
</platform>
</platforms>
</extension>
As I am not packaging the game for iPhone-ARM
nor do I have the libChartboostAir.a
file, I commented that platform
block using XML comments <!-- -->
.
We can see that there is a default
platform (I noticed that all extensions have one). So, I created a directory for the default
platform and copied library.swf
from the Android-ARM
directory to it. Then placed both directories inside a platform
directory. The directory structure now looks like this:
AIRSDK_Windows\bin
├── com.adobe.ane.social
├── com.milkmangames.extensions.AndroidIAB
├── com.chartboost.plugin.air
│ ├── com.chartboost.plugin.air.swc
│ ├── extension.xml
│ ├── platform
│ │ ├── Android-ARM
│ │ │ ├── library.swf
│ │ │ ├── <other bunch of files>
│ │ ├── default
│ │ │ ├── library.swf
├── com.milkmangames.extensions.CoreMobile
├── com.jirbo.airadc.AirAdColony
├── com.milkmangames.extensions.GoViral
Then, from the JAR file that we got at the beginning (converted from classes.dex
), I got all the classes related to com.chartboost.plugin.air
and placed them in a ZIP archive named libChartboostAir.jar
. I then placed libChartboostAir.jar
inside the Android-ARM
directory.
Finally, for this extension, I ran the following command to generate the ANE file:
..\adt.bat -package -target ane com.chartboost.plugin.air.ane extension.xml -swc com.chartboost.plugin.air.swc -platform Android-ARM -C platform/Android-ARM . -platform default -C platform/default library.swf
I generated the ANE files for the other extensions following the above steps. At the end, there were some classes in the JAR file (generated from classes.dex
) that I hadn't placed in the JAR file from any extension, because I did not know where they belonged. So, I just placed them in a random extension's JAR file. This wasn't a problem because what matters is that all classes end up being placed in the new classes.dex
file, using the same directory structure as the original.
Once all ANE files were compiled, I created a directory in the bin
directory for the app that I want to repackage.
Inside the original APK's assets
directory, there were the app's SWF file and a _Pic_Gen
directory with the app's icons. I placed them both in the directory I just created. And in the original APK's /assets/META-INF/AIR/
directory there were an application.xml
file and an extensions
directory (with the unpacked ANEs). I placed the application.xml
file inside the directory I created for the app in the bin
directory. Inside this directory, I also created an extensions
directory and placed the compiled ANE files inside. So, the directory structure for this app now looks like this:
AIRSDK_Windows\bin
├── MyApp
│ ├── application.xml
│ ├── _Pic_Gen
│ ├── MyApp.swf
│ ├── extensions
│ │ ├── com.adobe.ane.social.ane
│ │ ├── com.milkmangames.extensions.AndroidIAB.ane
│ │ ├── com.chartboost.plugin.air.ane
│ │ ├── com.milkmangames.extensions.CoreMobile.ane
│ │ ├── com.jirbo.airadc.AirAdColony.ane
│ │ └── com.milkmangames.extensions.GoViral.ane
I changed the targetSdkVersion
in the manifest inside application.xml
to 30, in order to support Android 11 (currently the latest). Android version and SDK correlation: https://developer.android.com/studio/releases/platforms
I also changed <application xmlns="http://ns.adobe.com/air/application/17.0">
to <application xmlns="http://ns.adobe.com/air/application/33.1">
, so that it uses the latest Flash Player version (33.1 is from HARMAN).
Then, I created a self-signed certificate using OpenSSL (I used Linux for this):
openssl req -newkey rsa:2048 -x509 -keyout cakey.pem -out cacert.pem -days 10000
# entered my password
openssl pkcs12 -export -in cacert.pem -inkey cakey.pem -out myapp.p12
And finally, I could package the new APK, using:
..\adt.bat -package -target apk -storetype pkcs12 -keystore myapp.p12 MyApp.apk application.xml -extdir extensions MyApp.swf _Pic_Gen
# entered certificate's password
Edit 2021-05-19 (Edit 2022-02-19: This step is no longer necessary with the latest Adobe AIR by HARMAN.)
However, for Android 11 and above, the APK must now be signed using APK Signature Scheme v2 or higher (see this: https://stackoverflow.com/a/66041713/3049315). Using apksigner
(available in Android SDK), you may do this as follows:
C:\Users\<user>\AppData\Local\Android\Sdk\build-tools\<version>\apksigner.bat sign -v --out MyApp_v2signed.apk --ks myapp.p12 MyApp.apk
The APK was then generated and I could play the game on recent Android versions.
Edit 2021-06-25
Apparently on some devices there would be an error on opening the APK saying "There was a problem parsing this package".
The error that I was getting when profiling the APK with Android Studio was: INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED
Then I came across this issue in AIR SDK. Opening AIRSDK_Windows\lib\adt.cfg
showed me the commented line:
#UncompressedExtensions=emd,tfl,tflite,pb
I uncommented it and added the arsc
extension to it, which is the extension of the file resources.arsc that Android Studio was complaining about. This fixed the issue after repackaging the APK with the new configuration.
Edit 2022-02-11
With the latest Adobe AIR, the following line should be added to the application.xml
file under the <android>
section if one does not wish to use the Android SDK for building. See: https://github.com/airsdk/Adobe-Runtime-Support/issues/1527#issuecomment-1007293682
<BuildLegacyAPK>true</BuildLegacyAPK>
Another option is to use the Android SDK for building, in which case the following lines should be added in the file AIRSDK_Windows\lib\adt.cfg
(replace with correct paths):
AndroidPlatformSDK=C:/Users/<user>/AppData/Local/Android/Sdk
JAVA_HOME=C:/Program Files/Java/jdk-11.0.14
Note that Java 11 or above must be used.
Furthermore, Android 12 now requires receivers with intent filters to have the attribute android:exported
. Example:
<receiver android:name="com.milkmangames.extensions.android.CMBootReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>