Difference between revisions of "Game Distribution/APKTool"

m (Sign APK warning!)
 
(30 intermediate revisions by 5 users not shown)
Line 2: Line 2:
 
To distribute your game for Android using APKTool:
 
To distribute your game for Android using APKTool:
  
{{notice|FIXME: '''This method is shouldn't be used for 11.1 APK and earlier!''' Google requires that all apps in Play Store must be compatible with API level 26 and compiled for ARM64, which isn't the case for LOVE 11.1 APK.}}
+
{{notice|'''Note:''' APK is the format used to distribute your games independently for Android and is still supported by some of the smaller app stores. [https://android-developers.googleblog.com/2020/08/recent-android-app-bundle-improvements.html Google Play Store mandate Android Application Bundle since 2021], thus this method is '''not suitable''' if you're looking to distribute your app into Play Store}}
 +
{{notice|Some notes before performing this method:
 +
1. This method assume '''you have PC or Mac available'''.
 +
 
 +
2. Make sure to specify valid, acceptable package name and '''sign the APK''' afterwards! Often errors include "Problem parsing package" and "App not installed" error. If you sure it's already signed and has valid package name, try installing via ADB.}}
  
 
1. Download [https://ibotpeaches.github.io/Apktool/install/ APKTool] and follow the installation instructions.
 
1. Download [https://ibotpeaches.github.io/Apktool/install/ APKTool] and follow the installation instructions.
  
2. Download LÖVE APK from the [https://love2d.org/ main page] and put it somewhere in folder.
+
2. Download latest LÖVE APK from [https://github.com/love2d/love-android/releases/download/11.5a/love-11.5-android-embed.apk here] and put it somewhere in folder.
  
3. In current folder (where you store the LÖVE APK), open Command Prompt/Terminal in the current directory and execute <code>apktool d -s -o love_decoded love-11.1-android.apk</code> and new folder <code>love_decoded</code> will be created. You can use any folder name, just make sure to make it consistent in later operations.
+
3. In current folder (where you store the LÖVE APK), open Command Prompt/Terminal in the current directory and execute <code>apktool d -s -o love_decoded love-11.5-android-embed.apk</code> and new folder <code>love_decoded</code> will be created. You can use any folder name, just make sure to make it consistent in later operations.
  
 
4. In <code>love_decoded</code> folder, create new folder named <code>assets</code> and put your <code>game.love</code> inside that folder. Your packaged game must be named exactly <code>game.love</code>!
 
4. In <code>love_decoded</code> folder, create new folder named <code>assets</code> and put your <code>game.love</code> inside that folder. Your packaged game must be named exactly <code>game.love</code>!
  
5. (Optional) Change the APK icon by replacing the LÖVE icon in <code>res/drawable-{mdpi,{x,{x,{x,}}}hdpi}</code> (mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi). Replace <code>love.png</code> with your game icon in those folders. Make sure the image dimensions are same!
+
5. Change the APK icon by replacing the LÖVE icon in <code>res/drawable-{mdpi,{x,{x,{x,}}}hdpi}</code> (mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi). Replace <code>love.png</code> with your game icon in those folders. Make sure the image dimensions are same!
  
 
6. Modify <code>AndroidManifest.xml</code> and use this template:
 
6. Modify <code>AndroidManifest.xml</code> and use this template:
   <source lang="xml"><?xml version="1.0" encoding="utf-8" standalone="no"?>
+
   <source lang="xml"><?xml version="1.0" encoding="utf-8"?>
 
<manifest package="${GamePackageName}"
 
<manifest package="${GamePackageName}"
      android:versionCode="${GameVersionCode}"
+
        android:versionCode="${GameVersionCode}"
      android:versionName="${GameVersionSemantic}"
+
        android:versionName="${GameVersionSemantic}"
      android:installLocation="auto" xmlns:android="http://schemas.android.com/apk/res/android">
+
        android:installLocation="auto"
     <uses-permission android:name="android.permission.INTERNET"/>
+
xmlns:android="http://schemas.android.com/apk/res/android">
     <uses-permission android:name="android.permission.VIBRATE"/>
+
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
+
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
+
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-feature android:glEsVersion="0x00020000"/>
+
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
 +
     <!--Uncomment line below if your game uses microphone capabilities. !-->
 +
    <!--uses-permission android:name="android.permission.RECORD_AUDIO" /!-->
 +
 
 +
    <!-- OpenGL ES 2.0 -->
 +
    <uses-feature android:glEsVersion="0x00020000" />
 +
    <!-- Touchscreen support -->
 +
    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
 +
    <!-- Game controller support -->
 +
    <uses-feature android:name="android.hardware.bluetooth" android:required="false" />
 +
    <uses-feature android:name="android.hardware.gamepad" android:required="false" />
 +
    <uses-feature android:name="android.hardware.usb.host" android:required="false" />
 +
    <!-- External mouse input events -->
 +
    <uses-feature android:name="android.hardware.type.pc" android:required="false" />
 +
    <!-- Low latency audio -->
 +
    <uses-feature android:name="android.hardware.audio.low_latency" android:required="false" />
 +
     <uses-feature android:name="android.hardware.audio.pro" android:required="false" />
 +
 
 
     <application
 
     <application
        android:allowBackup="true"
+
            android:allowBackup="true"
        android:icon="@drawable/love"
+
            android:icon="@drawable/love"
        android:label="${GameName}"
+
            android:label="${GameName}"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+
            android:usesCleartextTraffic="true" >
    >
 
 
         <activity
 
         <activity
            android:configChanges="orientation|screenSize"
+
                android:name="org.love2d.android.GameActivity"
            android:label="${GameName}"
+
                android:exported="true"
            android:launchMode="singleTop"
+
                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
             android:name="org.love2d.android.GameActivity"
+
                android:label="${GameName}"
            android:screenOrientation="sensorLandscape"
+
                android:launchMode="singleInstance"
        >
+
                android:screenOrientation="${ORIENTATION}"
 +
                android:resizeableActivity="false"
 +
                android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
 +
             <intent-filter>
 +
                <action android:name="android.intent.action.MAIN" />
 +
                <category android:name="android.intent.category.LAUNCHER" />
 +
                <category android:name="tv.ouya.intent.category.GAME" />
 +
            </intent-filter>
 
             <intent-filter>
 
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
+
                 <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
                <category android:name="android.intent.category.LAUNCHER"/>
 
                <category android:name="tv.ouya.intent.category.GAME"/>
 
 
             </intent-filter>
 
             </intent-filter>
 
         </activity>
 
         </activity>
 
     </application>
 
     </application>
 
</manifest></source>
 
</manifest></source>
   Here are the explanation of the variables:
+
   Here are the explanation of the variables. You just have to substitute them:
 
   * <code>${GamePackageName}</code> is your game internal package name.
 
   * <code>${GamePackageName}</code> is your game internal package name.
 
   * <code>${GameVersionCode}</code> is the internal APK version code.
 
   * <code>${GameVersionCode}</code> is the internal APK version code.
 
   * <code>${GameVersionSemantic}</code> is the readable APK version string. Example: 2.1.0
 
   * <code>${GameVersionSemantic}</code> is the readable APK version string. Example: 2.1.0
 
   * <code>${GameName}</code> is your game name which is going to be displayed in home screen/launcher.
 
   * <code>${GameName}</code> is your game name which is going to be displayed in home screen/launcher.
 +
  Make sure to substitute those variables.
  
 
7. Back to folder where you put the LÖVE APK then execute <code>apktool b -o your_game.apk love_decoded</code>. You can use any name, but again, make it consistent.
 
7. Back to folder where you put the LÖVE APK then execute <code>apktool b -o your_game.apk love_decoded</code>. You can use any name, but again, make it consistent.
  
8. '''Sign the resulting APK!!!'' This page doesn't cover how to do that, because it can be too long. You can't install the APK if it's not signed!!!
+
8. '''Sign the resulting APK!!!''' This page doesn't cover how to do that, because it can be too long. '''You can't install the APK if it's not signed!!!'''. Hint: https://github.com/patrickfav/uber-apk-signer
 +
 
 +
If you find something is wrong or having some problems, don't hesitate to edit or mention me in LOVE Discord: "auahdark".
 +
 
 +
== Termux ==
 +
{{notice|Using Termux is not supported. Proceed at your own risk (YMMV)!}}
 +
You can also create APKs from your Android device directly with the help of [https://termux.dev Termux].
 +
 
 +
1. [https://f-droid.org/en/packages/com.termux Install Termux from F-Droid].
 +
 
 +
2. Install [https://github.com/rendiix/termux-apktool termux-apktool].
 +
 
 +
3. Follow the instructions above as usual.
 +
 
 +
== See Also ==
 +
* [[Game Distribution]]
 +
 
 +
{{#set:Since=112}}
 +
{{#set:PrettySince=11.2}}
  
If you find something is wrong or having some problems, don't heistate to edit or mention me in LOVE Discord: "AuahDark#4586".
+
== Other Languages ==
 +
{{i18n|Game_Distribution/APKTool}}

Latest revision as of 09:04, 4 October 2024

This method will assume the usage of APKTool. To distribute your game for Android using APKTool:

O.png Note: APK is the format used to distribute your games independently for Android and is still supported by some of the smaller app stores. Google Play Store mandate Android Application Bundle since 2021, thus this method is not suitable if you're looking to distribute your app into Play Store  


O.png Some notes before performing this method:

1. This method assume you have PC or Mac available.

2. Make sure to specify valid, acceptable package name and sign the APK afterwards! Often errors include "Problem parsing package" and "App not installed" error. If you sure it's already signed and has valid package name, try installing via ADB.

 


1. Download APKTool and follow the installation instructions.

2. Download latest LÖVE APK from here and put it somewhere in folder.

3. In current folder (where you store the LÖVE APK), open Command Prompt/Terminal in the current directory and execute apktool d -s -o love_decoded love-11.5-android-embed.apk and new folder love_decoded will be created. You can use any folder name, just make sure to make it consistent in later operations.

4. In love_decoded folder, create new folder named assets and put your game.love inside that folder. Your packaged game must be named exactly game.love!

5. Change the APK icon by replacing the LÖVE icon in res/drawable-{mdpi,{x,{x,{x,}}}hdpi} (mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi). Replace love.png with your game icon in those folders. Make sure the image dimensions are same!

6. Modify AndroidManifest.xml and use this template:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="${GamePackageName}"
        android:versionCode="${GameVersionCode}"
        android:versionName="${GameVersionSemantic}"
        android:installLocation="auto"
		xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
    <!--Uncomment line below if your game uses microphone capabilities. !-->
    <!--uses-permission android:name="android.permission.RECORD_AUDIO" /!-->

    <!-- OpenGL ES 2.0 -->
    <uses-feature android:glEsVersion="0x00020000" />
    <!-- Touchscreen support -->
    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
    <!-- Game controller support -->
    <uses-feature android:name="android.hardware.bluetooth" android:required="false" />
    <uses-feature android:name="android.hardware.gamepad" android:required="false" />
    <uses-feature android:name="android.hardware.usb.host" android:required="false" />
    <!-- External mouse input events -->
    <uses-feature android:name="android.hardware.type.pc" android:required="false" />
    <!-- Low latency audio -->
    <uses-feature android:name="android.hardware.audio.low_latency" android:required="false" />
    <uses-feature android:name="android.hardware.audio.pro" android:required="false" />

    <application
            android:allowBackup="true"
            android:icon="@drawable/love"
            android:label="${GameName}"
            android:usesCleartextTraffic="true" >
        <activity
                android:name="org.love2d.android.GameActivity"
                android:exported="true"
                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
                android:label="${GameName}"
                android:launchMode="singleInstance"
                android:screenOrientation="${ORIENTATION}"
                android:resizeableActivity="false"
                android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="tv.ouya.intent.category.GAME" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
        </activity>
    </application>
</manifest>
 Here are the explanation of the variables. You just have to substitute them:
 * ${GamePackageName} is your game internal package name.
 * ${GameVersionCode} is the internal APK version code.
 * ${GameVersionSemantic} is the readable APK version string. Example: 2.1.0
 * ${GameName} is your game name which is going to be displayed in home screen/launcher.
 Make sure to substitute those variables.

7. Back to folder where you put the LÖVE APK then execute apktool b -o your_game.apk love_decoded. You can use any name, but again, make it consistent.

8. Sign the resulting APK!!! This page doesn't cover how to do that, because it can be too long. You can't install the APK if it's not signed!!!. Hint: https://github.com/patrickfav/uber-apk-signer

If you find something is wrong or having some problems, don't hesitate to edit or mention me in LOVE Discord: "auahdark".

Termux

O.png Using Termux is not supported. Proceed at your own risk (YMMV)!  


You can also create APKs from your Android device directly with the help of Termux.

1. Install Termux from F-Droid.

2. Install termux-apktool.

3. Follow the instructions above as usual.

See Also



Other Languages