def unpack_ant(interface): if os.path.exists(plat.path("apache-ant")): interface.success("Apache ANT has already been unpacked.") return archive = "apache-ant-1.8.4-bin.tar.gz" unpacked = "apache-ant-1.8.4" url = "http://archive.apache.org/dist/ant/binaries/" + archive interface.info("I'm downloading Apache Ant. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting Apache Ant.") def extract(): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() interface.background(extract) plat.rename(plat.path(unpacked), plat.path("apache-ant")) interface.success("I've finished unpacking Apache Ant.")
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_{}-windows.zip".format(plat.sdk_version) unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_{}-macosx.zip".format(plat.sdk_version) unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_{}-linux.tgz".format(plat.sdk_version) unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has a old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall(".") os.chdir(old_cwd) zf.close() interface.background(extract) plat.rename(plat.path(unpacked, replace=False), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def split_renpy(directory): """ Takes a built Ren'Py game, and splits it into the private and assets directories. This also renames <game>.py to main.py, and moves common/ into assets. """ private = os.path.join(directory, "private") assets = os.path.join(directory, "assets") filenames = os.listdir(directory) os.mkdir(private) os.mkdir(assets) os.mkdir(os.path.join(assets, "renpy")) plat.rename(os.path.join(directory, "renpy", "common"), os.path.join(assets, "renpy", "common")) for fn in filenames: full_fn = os.path.join(directory, fn) if fn.startswith("android-"): continue if fn.endswith(".py"): plat.rename(full_fn, os.path.join(private, "main.py")) continue if fn == "renpy": plat.rename(full_fn, os.path.join(private, fn)) continue plat.rename(full_fn, os.path.join(assets, fn)) return private, assets
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_r20-windows.zip" unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_r20-macosx.zip" unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_r20-linux.tgz" unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) zf.extractall(plat.path(".")) zf.close() interface.background(extract) plat.rename(plat.path(unpacked), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_{}-windows.zip".format(plat.sdk_version) unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_{}-macosx.zip".format(plat.sdk_version) unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_{}-linux.tgz".format(plat.sdk_version) unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) zf.extractall(plat.path(".")) zf.close() interface.background(extract) plat.rename(plat.path(unpacked, replace=False), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def make_assets(): if assets_dir is not None: make_tree(assets_dir, assets) else: os.mkdir(assets) # If we're Ren'Py, rename things. if RENPY: # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(assets, topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new)
def make_assets(): if assets_dir is not None: make_tree(assets_dir, plat.path("assets")) else: os.mkdir(plat.path("assets")) # If we're Ren'Py, rename things. if os.path.exists(plat.path("assets/renpy")): # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(plat.path("assets"), topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new)
def build(iface, directory, commands, launch=False, finished=None): # Modify to ask for a Keystore password if none exists # or add setting to build for production # Are we doing a Ren'Py build? global RENPY RENPY = plat.renpy if not os.path.isdir(directory): iface.fail("{} is not a directory.".format(directory)) if RENPY and not os.path.isdir(os.path.join(directory, "game")): iface.fail("{} does not contain a Ren'Py game.".format(directory)) config = configure.Configuration(directory) if config.package is None: iface.fail("Run configure before attempting to build the app.") if (config.store == "play" or config.store == "all") and (config.google_play_key is None): iface.fail("Google Play support is enabled, but build.google_play_key is not set. Please set in your game.") global blacklist global whitelist blacklist = PatternList("blacklist.txt") whitelist = PatternList("whitelist.txt") if RENPY: manifest_extra = None default_icon = plat.path("templates/renpy-icon.png") default_presplash = plat.path("templates/renpy-presplash.jpg") public_dir = None private_dir, assets_dir = split_renpy(directory) else: manifest_extra = "" default_icon = plat.path("templates/pygame-icon.png") default_presplash = plat.path("templates/pygame-presplash.jpg") if config.layout == "internal": private_dir = directory public_dir = None assets_dir = None elif config.layout == "external": private_dir = None public_dir = directory assets_dir = None elif config.layout == "split": private_dir = join_and_check(directory, "internal") public_dir = join_and_check(directory, "external") assets_dir = join_and_check(directory, "assets") versioned_name = config.name versioned_name = re.sub(r'[^\w]', '', versioned_name) versioned_name += "-" + config.version # Annoying fixups. config.name = config.name.replace("'", "\\'") config.icon_name = config.icon_name.replace("'", "\\'") if config.store not in [ "play", "none" ]: config.expansion = False # Figure out versions of the private and public data. private_version = str(time.time()) if public_dir: public_version = private_version else: public_version = None # Render the various templates into control files. render( "AndroidManifest.tmpl.xml", "AndroidManifest.xml", config = config, manifest_extra = manifest_extra, ) render( "strings.xml", "res/values/strings.xml", public_version = public_version, private_version = private_version, config = config) try: os.unlink(plat.path("build.xml")) except: pass iface.info("Updating source code.") edit_file("src/org/renpy/android/DownloaderActivity.java", r'import .*\.R;', 'import {}.R;'.format(config.package)) iface.info("Updating build files.") # Update the project to a recent version. if os.path.exists(plat.path("project.properties")): os.unlink(plat.path("project.properties")) iface.call([plat.android, "update", "project", "-p", '.', '-t', plat.target, '-n', versioned_name, "--library", plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library", relative=True), ]) iface.info("Creating assets directory.") if os.path.isdir(plat.path("assets")): shutil.rmtree(plat.path("assets")) def make_assets(): if assets_dir is not None: make_tree(assets_dir, plat.path("assets")) else: os.mkdir(plat.path("assets")) # If we're Ren'Py, rename things. if os.path.exists(plat.path("assets/renpy")): # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(plat.path("assets"), topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new) iface.background(make_assets) if config.expansion: iface.info("Creating expansion file.") expansion_file = "main.{}.{}.obb".format(config.numeric_version, config.package) def make_expansion(): zf = zipfile.ZipFile(plat.path(expansion_file), "w", zipfile.ZIP_STORED) zip_directory(zf, "assets") zf.close() # Delete and re-make the assets directory. shutil.rmtree(plat.path("assets")) os.mkdir(plat.path("assets")) iface.background(make_expansion) # Write the file size into DownloaderActivity. file_size = os.path.getsize(plat.path(expansion_file)) else: expansion_file = None file_size = 0 # Write out constants.java. if not config.google_play_key: config.google_play_key = "NOT_SET" if not config.google_play_salt: config.google_play_salt = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20" render( "Constants.java", "src/org/renpy/android/Constants.java", config = config, file_size = file_size) iface.info("Packaging internal data.") private_dirs = [ 'private' ] if private_dir is not None: private_dirs.append(private_dir) if os.path.exists(plat.path("engine-private")): private_dirs.append(plat.path("engine-private")) def pack(): make_tar(iface, plat.path("assets/private.mp3"), private_dirs) iface.background(pack) if public_dir is not None: iface.info("Packaging external data.") make_tar(iface, plat.path("assets/public.mp3"), [ public_dir ]) # Copy over the icon files. copy_icon(directory, "icon.png", default_icon) # Copy the presplash files. copy_presplash(directory, "android-presplash", default_presplash) # Copy over the OUYA icon. ouya_icon = join_and_check(directory, "ouya-icon.png") or join_and_check(directory, "ouya_icon.png") if ouya_icon: if not os.path.exists(plat.path("res/drawable-xhdpi")): os.mkdir(plat.path("res/drawable-xhdpi")) shutil.copy(ouya_icon, plat.path("res/drawable-xhdpi/ouya_icon.png")) # Build. iface.info("I'm using Ant to build the package.") files = [ ] try: # Clean is required, so we don't use old code. (Not true anymore?) # iface.call([plat.ant, "clean" ] + commands, cancel=True) iface.call([ plat.ant ] + commands, cancel=True) files.append(plat.path("bin/" + versioned_name + "-release.apk")) if (expansion_file is not None) and ("install" in commands): iface.info("Uploading expansion file.") dest = "/mnt/sdcard/{}".format(expansion_file) iface.call([ plat.adb, "push", plat.path(expansion_file), dest ], cancel=True) if expansion_file is not None: plat.rename(plat.path(expansion_file), plat.path("bin/" + expansion_file)) files.append(plat.path("bin/" + expansion_file)) except subprocess.CalledProcessError: iface.fail("The build seems to have failed.") if launch: iface.info("Launching app.") if expansion_file: launch_activity = "DownloaderActivity" else: launch_activity = "PythonSDLActivity" iface.call([ plat.adb, "shell", "am", "start", "-W", "-a", "android.intent.action.MAIN", "{}/org.renpy.android.{}".format(config.package, launch_activity), ], cancel=True) if finished is not None: finished(files) iface.final_success("The build seems to have succeeded.")
def build(iface, directory, commands): # Are we doing a Ren'Py build? global RENPY RENPY = plat.renpy if not os.path.isdir(directory): iface.fail("{} is not a directory.".format(directory)) if RENPY and not os.path.isdir(os.path.join(directory, "game")): iface.fail("{} does not contain a Ren'Py game.".format(directory)) config = configure.Configuration(directory) if config.package is None: iface.fail("Run configure before attempting to build the app.") global blacklist global whitelist blacklist = PatternList("blacklist.txt") whitelist = PatternList("whitelist.txt") if RENPY: manifest_extra = None default_icon = plat.path("templates/renpy-icon.png") default_presplash = plat.path("templates/renpy-presplash.jpg") public_dir = None private_dir = None assets_dir = directory else: manifest_extra = "" default_icon = plat.path("templates/pygame-icon.png") default_presplash = plat.path("templates/pygame-presplash.jpg") if config.layout == "internal": private_dir = directory public_dir = None assets_dir = None elif config.layout == "external": private_dir = None public_dir = directory assets_dir = None elif config.layout == "split": private_dir = join_and_check(directory, "internal") public_dir = join_and_check(directory, "external") assets_dir = join_and_check(directory, "assets") versioned_name = config.name.replace(" ", "").replace("'", "") + "-" + config.version # Annoying fixups. config.name = config.name.replace("'", "\\'") config.icon_name = config.icon_name.replace("'", "\\'") # Figure out versions of the private and public data. private_version = str(time.time()) if public_dir: public_version = private_version else: public_version = None # Render the various templates into control files. render( "AndroidManifest.tmpl.xml", "AndroidManifest.xml", config = config, manifest_extra = manifest_extra, ) render( "strings.xml", "res/values/strings.xml", public_version = public_version, private_version = private_version, config = config) try: os.unlink(plat.path("build.xml")) except: pass iface.info("Updating source code.") edit_file("src/org/renpy/android/DownloaderActivity.java", r'import .*\.R;', 'import {}.R;'.format(config.package)) iface.info("Updating build files.") # Update the project to a recent version. iface.call([plat.android, "update", "project", "-p", '.', '-t', 'android-8', '-n', versioned_name, # "--library", "android-sdk/extras/google/play_licensing/library", "--library", plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library", relative=True), ]) iface.info("Creating assets directory.") if os.path.isdir(plat.path("assets")): shutil.rmtree(plat.path("assets")) def make_assets(): if assets_dir is not None: make_tree(assets_dir, plat.path("assets")) else: os.mkdir(plat.path("assets")) # If we're Ren'Py, rename things. if os.path.exists(plat.path("assets/renpy")): # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(plat.path("assets"), topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new) iface.background(make_assets) if config.expansion: iface.info("Creating expansion file.") expansion_file = "main.{}.{}.obb".format(config.numeric_version, config.package) def make_expansion(): zf = zipfile.ZipFile(plat.path(expansion_file), "w", zipfile.ZIP_STORED) zip_directory(zf, "assets") zf.close() # Delete and re-make the assets directory. shutil.rmtree(plat.path("assets")) os.mkdir(plat.path("assets")) iface.background(make_expansion) # Write the file size into DownloaderActivity. file_size = os.path.getsize(plat.path(expansion_file)) edit_file("src/org/renpy/android/DownloaderActivity.java", r' private int fileVersion =', ' private int fileVersion = {};'.format(config.numeric_version)) edit_file("src/org/renpy/android/DownloaderActivity.java", r' private int fileSize =', ' private int fileSize = {};'.format(file_size)) else: expansion_file = None # Update the GP key and salt. if config.google_play_key: edit_file("src/org/renpy/android/DownloaderService.java", r' private static final String BASE64_PUBLIC_KEY', ' private static final String BASE64_PUBLIC_KEY = "%s";' % config.google_play_key) if config.google_play_salt: edit_file("src/org/renpy/android/DownloaderService.java", r' private static final byte\[\] SALT', ' private static final byte[] SALT = new byte[] { %s };' % config.google_play_salt) iface.info("Packaging internal data.") private_dirs = [ 'private' ] if private_dir is not None: private_dirs.append(private_dir) if os.path.exists(plat.path("engine-private")): private_dirs.append(plat.path("engine-private")) def pack(): make_tar(plat.path("assets/private.mp3"), private_dirs) iface.background(pack) if public_dir is not None: iface.info("Packaging external data.") make_tar(plat.path("assets/public.mp3"), [ public_dir ]) # Copy over the icon and presplash files. copy_icon(directory, "icon.png", default_icon) copy_icon(directory, "presplash.jpg", default_presplash) # Copy over the OUYA icon. ouya_icon = join_and_check(directory, "ouya-icon.png") or join_and_check(directory, "ouya_icon.png") if ouya_icon: if not os.path.exists(plat.path("res/drawable-xhdpi")): os.mkdir(plat.path("res/drawable-xhdpi")) shutil.copy(ouya_icon, plat.path("res/drawable-xhdpi/ouya_icon.png")) # Build. iface.info("I'm using Ant to build the package.") try: # Clean is required, so we don't use old code. iface.call([plat.ant, "clean"] + commands, cancel=True) if (expansion_file is not None) and ("install" in commands): iface.info("Uploading expansion file.") dest = "/mnt/sdcard/{}".format(expansion_file) iface.call([ plat.adb, "push", plat.path(expansion_file), dest ], cancel=True) if expansion_file is not None: plat.rename(plat.path(expansion_file), plat.path("bin/" + expansion_file)) except subprocess.CalledProcessError: iface.fail("The build seems to have failed.") iface.final_success("The build seems to have succeeded.")