简体   繁体   English

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

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

If I understand well, once ARCore 1.0 will be released on Google Play, it will be necessary to install it on the device in order to be able to run an ARCore app.如果我理解得很好,一旦 ARCore 1.0 将在 Google Play 上发布,就必须在设备上安装它才能运行 ARCore 应用程序。

How to check if ARCore lib/apk is installed on device ?如何检查设备上是否安装了 ARCore lib/apk?

Should be sufficient to do something like:应该足以执行以下操作:

    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")
    }

This is what I'm using here for one my apps and works fine on devices with or wothout ARCore.这就是我在这里用于我的一个应用程序的内容,并且在带有或不带有 ARCore 的设备上都可以正常工作。

According to ARCore documentation 1.4.0 , if optional it is important check its availability recursively and then install it:根据ARCore 文档 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);
  }
}

If already supported just check if ARCore is installed:如果已经支持,只需检查是否安装了 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
}

Sometimes it is easier to request this with Rx methodology.有时使用 Rx 方法更容易提出请求。 Here's the code:这是代码:

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())
}

Here's a little utility class I wrote (based originally on something from https://github.com/google/helloargdx ).这是我编写的一个小实用程序类(最初基于https://github.com/google/helloargdx 中的内容)。

It will perform all the checks and setup necessary, in order to ensure it is safe to launch a Session .它将执行所有必要的检查和设置,以确保启动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
    }
}

You can subclass this Fragment and implement the abstract functions to receive callbacks on what the result of these checks is.您可以子类化此 Fragment 并实现抽象函数以接收有关这些检查结果的回调。 Only in onArCoreInstallSuccess is it safe to create a Session .只有在onArCoreInstallSuccess中创建Session是安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM