docs: def apk(self, args):
          """Create an APK using the given distribution."""
  
          ctx = self.ctx
          dist = self._dist
  
          # Manually fixing these arguments at the string stage is
          # unsatisfactory and should probably be changed somehow, but
          # we can't leave it until later as the build.py scripts assume
          # they are in the current directory.
          fix_args = ('--dir', '--private', '--add-jar', '--add-source',
                      '--whitelist', '--blacklist', '--presplash', '--icon')
          unknown_args = args.unknown_args
          for i, arg in enumerate(unknown_args):
              argx = arg.split('=')
              if argx[0] in fix_args:
                  if len(argx) > 1:
                      unknown_args[i] = '='.join(
                          (argx[0], realpath(expanduser(argx[1]))))
                  elif i + 1 < len(unknown_args):
                      unknown_args[i+1] = realpath(expanduser(unknown_args[i+1]))
  
          env = os.environ.copy()
          if args.build_mode == 'release':
              if args.keystore:
                  env['P4A_RELEASE_KEYSTORE'] = realpath(expanduser(args.keystore))
              if args.signkey:
                  env['P4A_RELEASE_KEYALIAS'] = args.signkey
              if args.keystorepw:
                  env['P4A_RELEASE_KEYSTORE_PASSWD'] = args.keystorepw
              if args.signkeypw:
                  env['P4A_RELEASE_KEYALIAS_PASSWD'] = args.signkeypw
              elif args.keystorepw and 'P4A_RELEASE_KEYALIAS_PASSWD' not in env:
                  env['P4A_RELEASE_KEYALIAS_PASSWD'] = args.keystorepw
  
          build = imp.load_source('build', join(dist.dist_dir, 'build.py'))
          with current_directory(dist.dist_dir):
              self.hook("before_apk_build")
              os.environ["ANDROID_API"] = str(self.ctx.android_api)
              build_args = build.parse_args(args.unknown_args)
              self.hook("after_apk_build")
              self.hook("before_apk_assemble")
  
              build_type = ctx.java_build_tool
              if build_type == 'auto':
                  info('Selecting java build tool:')
  
                  build_tools_versions = os.listdir(join(ctx.sdk_dir,
                                                         'build-tools'))
                  build_tools_versions = sorted(build_tools_versions,
                                                key=LooseVersion)
                  build_tools_version = build_tools_versions[-1]
                  info(('Detected highest available build tools '
                        'version to be {}').format(build_tools_version))
  
                  if build_tools_version >= '25.0' and exists('gradlew'):
                      build_type = 'gradle'
                      info('    Building with gradle, as gradle executable is '
                           'present')
                  else:
                      build_type = 'ant'
                      if build_tools_version < '25.0':
                          info(('    Building with ant, as the highest '
                                'build-tools-version is only {}').format(
                              build_tools_version))
                      else:
                          info('    Building with ant, as no gradle executable '
                               'detected')
  
              if build_type == 'gradle':
                  # gradle-based build
                  env["ANDROID_NDK_HOME"] = self.ctx.ndk_dir
                  env["ANDROID_HOME"] = self.ctx.sdk_dir
  
                  gradlew = sh.Command('./gradlew')
                  if exists('/usr/bin/dos2unix'):
                      # .../dists/bdisttest_python3/gradlew
                      # .../build/bootstrap_builds/sdl2-python3crystax/gradlew
                      # if docker on windows, gradle contains CRLF
                      output = shprint(
                          sh.Command('dos2unix'), gradlew._path.decode('utf8'),
                          _tail=20, _critical=True, _env=env
                      )
                  if args.build_mode == "debug":
                      gradle_task = "assembleDebug"
                  elif args.build_mode == "release":
                      gradle_task = "assembleRelease"
                  else:
                      raise BuildInterruptingException(
                          "Unknown build mode {} for apk()".format(args.build_mode))
                  output = shprint(gradlew, gradle_task, _tail=20,
                                   _critical=True, _env=env)
  
                  # gradle output apks somewhere else
                  # and don't have version in file
                  apk_dir = join(dist.dist_dir,
                                 "build", "outputs", "apk",
                                 args.build_mode)
                  apk_glob = "*-{}.apk"
                  apk_add_version = True
  
              else:
                  # ant-based build
                  try:
                      ant = sh.Command('ant')
                  except sh.CommandNotFound:
                      raise BuildInterruptingException(
                          'Could not find ant binary, please install it '
                          'and make sure it is in your $PATH.')
                  output = shprint(ant, args.build_mode, _tail=20,
                                   _critical=True, _env=env)
                  apk_dir = join(dist.dist_dir, "bin")
                  apk_glob = "*-*-{}.apk"
                  apk_add_version = False
  
              self.hook("after_apk_assemble")
  
          info_main('# Copying APK to current directory')
  
          apk_re = re.compile(r'.*Package: (.*\.apk)$')
          apk_file = None
          for line in reversed(output.splitlines()):
              m = apk_re.match(line)
              if m:
                  apk_file = m.groups()[0]
                  break
  
          if not apk_file:
              info_main('# APK filename not found in build output. Guessing...')
              if args.build_mode == "release":
                  suffixes = ("release", "release-unsigned")
              else:
                  suffixes = ("debug", )
              for suffix in suffixes:
                  apks = glob.glob(join(apk_dir, apk_glob.format(suffix)))
                  if apks:
                      if len(apks) > 1:
                          info('More than one built APK found... guessing you '
                               'just built {}'.format(apks[-1]))
                      apk_file = apks[-1]
                      break
              else:
                  raise BuildInterruptingException('Couldn\'t find the built APK')
  
          info_main('# Found APK file: {}'.format(apk_file))
          if apk_add_version:
              info('# Add version number to APK')
              apk_name, apk_suffix = basename(apk_file).split("-", 1)
              apk_file_dest = "{}-{}-{}".format(
                  apk_name, build_args.version, apk_suffix)
              info('# APK renamed to {}'.format(apk_file_dest))
              shprint(sh.cp, apk_file, apk_file_dest)
          else:
              shprint(sh.cp, apk_file, './')