如何检查设备上是否安装了 ARCore lib/apk?

How to check if ARCore lib/apk installed on device?

如果我理解得很好,一旦 ARCore 1.0 将在 Google Play 上发布,就必须将其安装在设备上才能 运行 ARCore 应用程序。

如何检查设备上是否安装了 ARCore lib/apk?

应该足以执行以下操作:

    try {
        arCoreSession = Session(this)

        val config = Config(arCoreSession)
        if (!arCoreSession.isSupported(config)) {
            Logger.d("ARCore not installed")
        } else {
            arCoreSession.configure(config)
        }
    } catch (ex: Throwable) {
        Logger.d("ARCore not installed")
    }

这就是我在此处用于我的一个应用程序的内容,并且在具有或不具有 ARCore 的设备上都可以正常工作。

根据 ARCore documentation 1.4.0,如果可选,请务必递归检查其可用性,然后安装它:

void maybeEnableArButton() {
  // Likely called from Activity.onCreate() of an activity with AR buttons.
  ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
  if (availability.isTransient()) {
    // re-query at 5Hz while we check compatibility.
    new Handler().postDelayed(new Runnable() {
      @Override
      public void run() {
        maybeEnableArButton();
      }
    }, 200);
  }
  if (availability.isSupported()) {
    mArButton.setVisibility(View.VISIBLE);
    mArButton.setEnabled(true);
    // indicator on the button.
  } else { // unsupported or unknown
    mArButton.setVisibility(View.INVISIBLE);
    mArButton.setEnabled(false);
  }
}

如果已经支持,只需检查是否安装了 ARCore:

// Set to true ensures requestInstall() triggers installation if necessary.
private boolean mUserRequestedInstall = true;

// in onResume:
try {
  if (mSession == null) {
    switch (ArCoreApk.getInstance().requestInstall(this, mUserRequestedInstall)) {
      case INSTALLED:
        mSession = new Session(this);
        // Success.
        break;
      case INSTALL_REQUESTED:
        // Ensures next invocation of requestInstall() will either return
        // INSTALLED or throw an exception.
        mUserRequestedInstall = false;
        return;
    }
  }
} catch (UnavailableUserDeclinedInstallationException e) {
  // Display an appropriate message to the user and return gracefully.
  return;
} catch (...) {  // current catch statements
  ...
  return;  // mSession is still null
}

有时使用 Rx 方法更容易请求。这是代码:

private fun getArAvailabilityRx(context: Context): Single<ArCoreApk.Availability> {
    return Single.fromCallable<ArCoreApk.Availability> {
        ArCoreApk.getInstance().checkAvailability(context)
    }.flatMap { availability ->
        if (availability.isTransient) {
            // `isTransient` means it hasn't finished loading value; let's request the value in 500 ms
            getArAvailabilityRx(context).delaySubscription(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
        } else {
            Single.just(availability)
        }
    }.observeOn(AndroidSchedulers.mainThread())
}

这是我写的一个小工具 class(最初基于 https://github.com/google/helloargdx 中的内容)。

它将执行所有必要的检查和设置,以确保安全地启动 Session

abstract class ArCheckFragment : Fragment() {

    private var userRequestedInstall = true

    abstract fun onCameraPermissionDeny()

    abstract fun onArCoreUnavailable(availability: Availability)

    abstract fun onArCoreInstallFail(exception: UnavailableException)

    abstract fun onArCoreInstallSuccess()

    override fun onResume() {
        super.onResume()
        performCheck()
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) {
            for (i in permissions.indices) {
                if (permissions[i] == Manifest.permission.CAMERA &&
                    grantResults[i] == PackageManager.PERMISSION_GRANTED
                ) {
                    checkArCore()
                    return
                }
            }
            onCameraPermissionDeny()
        }
    }

    /**
     * Performs the whole check
     */
    fun performCheck() {
        if (requestCameraPermission()) {
            checkArCore()
        }
    }

    /**
     * Requests the camera permission, if necessary.
     * @return whether camera permission is already granted. If so, the permission won't be requested.
     */
    private fun requestCameraPermission(): Boolean {
        if (ContextCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            return true
        }
        requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CODE_CAMERA_PERMISSION)
        return false
    }

    private fun checkArCore() {
        if (!isResumed) {
            return
        }
        val availability = ArCoreApk.getInstance().checkAvailability(activity)
        if (availability.isTransient) {
            requireView().postDelayed(AR_CORE_CHECK_INTERVAL) { checkArCore() }
            return
        }
        when (availability) {
            Availability.SUPPORTED_INSTALLED ->
                onArCoreInstallSuccess()
            Availability.SUPPORTED_APK_TOO_OLD,
            Availability.SUPPORTED_NOT_INSTALLED ->
                startArCoreInstallation()
            else ->
                onArCoreUnavailable(availability)
        }
    }

    private fun startArCoreInstallation() {
        try {
            val installStatus =
                ArCoreApk.getInstance().requestInstall(activity, userRequestedInstall)
            when (installStatus) {
                InstallStatus.INSTALLED -> onArCoreInstallSuccess()
                InstallStatus.INSTALL_REQUESTED,
                null ->
                    // Ensures next invocation of requestInstall() will either return
                    // INSTALLED or throw an exception.
                    userRequestedInstall = false
            }
        } catch (exception: UnavailableException) {
            onArCoreInstallFail(exception)
        }
    }

    companion object {
        private const val REQUEST_CODE_CAMERA_PERMISSION = 1
        private const val AR_CORE_CHECK_INTERVAL = 200L
    }
}

您可以子class 这个 Fragment 并实现抽象函数来接收关于这些检查结果的回调。只有在 onArCoreInstallSuccess 中创建 Session.

才是安全的