Android NDK开发详解相机之CameraX 架构

本页介绍了 CameraX 的架构,包括其结构、如何与 API 搭配使用、如何与生命周期配合使用以及如何组合各种用例。

CameraX 结构

您可以使用 CameraX,借助名为“用例”的抽象概念与设备的相机进行交互。提供的用例如下:

预览:接受用于显示预览的 Surface,例如 PreviewView。
图片分析:为分析(例如机器学习)提供 CPU 可访问的缓冲区。
图片拍摄:拍摄并保存照片。
视频拍摄:通过 VideoCapture 拍摄视频和音频

不同用例可以组合使用,也可以同时处于活跃状态。例如,应用中可以加入预览用例,以便让用户查看进入相机视野的画面;加入图片分析用例,以确定照片里的人物是否在微笑;还可以加入图片拍摄用例,以在人物微笑时拍摄照片。

API 模型

如需使用该库,请指定以下内容:

具有配置选项的所需用例。
通过附加监听器来指定如何处理输出数据。
通过将用例绑定到 Android 架构生命周期来指定目标流程,例如何时启用相机及何时生成数据。

您可以通过 2 种方式编写 CameraX 应用:CameraController(如果您希望通过最简单的方式使用 CameraX,这非常适合)或 CameraProvider(如果需要更高的灵活性,这非常适合)。

CameraController

CameraController 在单个类中提供大多数 CameraX 核心功能。它只需少量设置代码,并且可自动处理相机初始化、用例管理、目标旋转、点按对焦、双指张合缩放等操作。扩展 CameraController 的具体类为 LifecycleCameraController。
Kotlin

val previewView: PreviewView = viewBinding.previewView
var cameraController = LifecycleCameraController(baseContext)
cameraController.bindToLifecycle(this)
cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
previewView.controller = cameraController

Java

PreviewView previewView = viewBinding.previewView;
LifecycleCameraController cameraController = new LifecycleCameraController(baseContext);
cameraController.bindToLifecycle(this);
cameraController.setCameraSelector(CameraSelector.DEFAULT_BACK_CAMERA);
previewView.setController(cameraController);

CameraController 的默认 UseCase 为 Preview、ImageCapture 和 ImageAnalysis。如需关闭 ImageCapture 或 ImageAnalysis,或者开启 VideoCapture,请使用 setEnabledUseCases() 方法。

如需了解 CameraController 的更多用法,请参阅二维码扫描器示例或 CameraController 基础知识视频。

CameraProvider

CameraProvider 仍然易于使用,但由于应用开发者会处理更多设置,因此有更多机会自定义配置,例如在 ImageAnalysis 中启用输出图片旋转或设置输出图像格式。您还可以使用自定义 Surface 进行相机预览以提高灵活性,而对于 CameraController,您需要使用 PreviewView。如果现有的 Surface 代码已是应用的其他部分的输入,则使用该代码会非常有用。

您可以使用 set() 方法配置用例,并使用 build() 方法完成这些用例。每个用例对象都提供一组特定于该用例的 API。例如,图片拍摄用例会提供 takePicture() 方法调用。

应用没有在 onResume() 和 onPause() 中放置具体的启动和停止方法调用,而是使用 cameraProvider.bindToLifecycle() 指定要与相机关联的生命周期。之后,该生命周期会告知 CameraX 何时配置相机拍摄会话并确保相机状态随生命周期的转换相应地变化。

如需了解每个用例的实现步骤,请参阅实现预览、分析图片、图片拍摄和视频拍摄

预览用例会与 Surface 互动以展示预览。应用使用以下代码创建具有配置选项的用例:
Kotlin

val preview = Preview.Builder().build()
val viewFinder: PreviewView = findViewById(R.id.previewView)

// The use case is bound to an Android Lifecycle with the following code
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// PreviewView creates a surface provider and is the recommended provider
preview.setSurfaceProvider(viewFinder.getSurfaceProvider())

Java

Preview preview = new Preview.Builder().build();
PreviewView viewFinder = findViewById(R.id.view_finder);

// The use case is bound to an Android Lifecycle with the following code
Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview);

// PreviewView creates a surface provider, using a Surface from a different
// kind of view will require you to implement your own surface provider.
preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();

如需查看更多示例代码,请参阅官方 CameraX 示例应用。

CameraX 生命周期

CameraX 会按照生命周期确定何时打开相机、何时创建拍摄会话以及何时停止和关闭。用例 API 提供方法调用和回调来监控进度情况。

如组合用例中所述,您可以将多个用例一起绑定到单个生命周期。当您的应用需要支持无法组合的用例时,您可以执行以下操作之一:

将兼容的用例划分到多个 Fragment 中,然后在 Fragment 之间进行切换
创建自定义生命周期组件并使用该组件来手动控制相机生命周期

如果您将视图用例和相机用例的生命周期所有者分开(例如,如果您使用自定义生命周期或保留 Fragment),则必须通过使用 ProcessCameraProvider.unbindAll() 或分别取消绑定各个用例来确保所有用例均未绑定 CameraX。或者,当您将用例绑定到生命周期时,可以让 CameraX 管理拍摄会话的开启和关闭操作以及用例的取消绑定操作。

如果所有相机功能都对应于单个生命周期感知型组件(例如 AppCompatActivity 或 AppCompat Fragment)的生命周期,那么在绑定全部所需用例时使用该组件的生命周期,可确保相机功能在该组件处于活动状态时准备就绪,并在该组件进入非活动状态时获得安全处置,而不会消耗任何资源。

自定义 LifecycleOwner

对于高级用例,您可以创建自定义 LifecycleOwner,以使您的应用显式控制 CameraX 会话生命周期,而不是将其绑定到标准 Android LifecycleOwner。

以下代码示例展示了如何创建简单的自定义 LifecycleOwner:
Kotlin

class CustomLifecycle : LifecycleOwner {
    private val lifecycleRegistry: LifecycleRegistry

    init {
        lifecycleRegistry = LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }
    ...
    fun doOnResume() {
        lifecycleRegistry.markState(State.RESUMED)
    }
    ...
    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

Java

public class CustomLifecycle implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;
    public CustomLifecycle() {
        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }
   ...
   public void doOnResume() {
        lifecycleRegistry.markState(State.RESUMED);
    }
   ...
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

借助此 LifecycleOwner,您的应用可以将状态转换放置在代码中所需的位置。如需详细了解如何在应用中实现此功能,请参阅实现自定义 LifecycleOwner。

并发用例

多个用例可以同时运行。虽然可以将多个用例依序绑定到一个生命周期,但最好通过对 CameraProcessProvider.bindToLifecycle() 的一次调用来绑定所有用例。如需详细了解配置更改的最佳做法,请参阅处理配置更改。

在以下代码示例中,应用指定了要创建并同时运行的两个用例,还指定了要同时用于这两个用例的生命周期,以便这两个用例都按照该生命周期启动和停止。
Kotlin

private lateinit var imageCapture: ImageCapture

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener(Runnable {
        // Camera provider is now guaranteed to be available
        val cameraProvider = cameraProviderFuture.get()

        // Set up the preview use case to display camera preview.
        val preview = Preview.Builder().build()

        // Set up the capture use case to allow users to take photos.
        imageCapture = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build()

        // Choose the camera by requiring a lens facing
        val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                .build()

        // Attach use cases to the camera with the same lifecycle owner
        val camera = cameraProvider.bindToLifecycle(
                this as LifecycleOwner, cameraSelector, preview, imageCapture)

        // Connect the preview use case to the previewView
        preview.setSurfaceProvider(
                previewView.getSurfaceProvider())
    }, ContextCompat.getMainExecutor(this))
}

Java

private ImageCapture imageCapture;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    PreviewView previewView = findViewById(R.id.previewView);

    ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
            ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            // Camera provider is now guaranteed to be available
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

            // Set up the view finder use case to display camera preview
            Preview preview = new Preview.Builder().build();

            // Set up the capture use case to allow users to take photos
            imageCapture = new ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    .build();

            // Choose the camera by requiring a lens facing
            CameraSelector cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(lensFacing)
                    .build();

            // Attach use cases to the camera with the same lifecycle owner
            Camera camera = cameraProvider.bindToLifecycle(
                    ((LifecycleOwner) this),
                    cameraSelector,
                    preview,
                    imageCapture);

            // Connect the preview use case to the previewView
            preview.setSurfaceProvider(
                    previewView.getSurfaceProvider());
        } catch (InterruptedException | ExecutionException e) {
            // Currently no exceptions thrown. cameraProviderFuture.get()
            // shouldn't block since the listener is being called, so no need to
            // handle InterruptedException.
        }
    }, ContextCompat.getMainExecutor(this));
}

保证可以支持以下配置组合(当单独需要“预览”或“视频拍摄”用例时):
在这里插入图片描述

如果同时需要“预览”和“视频拍摄”用例,则可以附条件地支持以下用例组合:
在这里插入图片描述

此外,

每个用例都可以单独使用。例如,应用可以在不使用预览的情况下录制视频。
启用扩展后,只能保证能够使用 ImageCapture 和 Preview 的组合。根据 OEM 实现情况,可能无法同时添加 ImageAnalysis;无法为 VideoCapture 用例启用扩展。如需了解详情,请参阅扩展参考文档。
对于某些相机而言,在较低分辨率模式下可以支持的组合,在较高的分辨率下将无法支持,这具体取决于相机的功能。

所支持的硬件级别可以从 Camera2CameraInfo 中检索。例如,以下代码可检查默认的后置摄像头是否是 LEVEL_3 设备:
Kotlin

@androidx.annotation.OptIn(ExperimentalCamera2Interop::class)
fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return CameraSelector.DEFAULT_BACK_CAMERA
            .filter(cameraProvider.availableCameraInfos)
            .firstOrNull()
            ?.let { Camera2CameraInfo.from(it) }
            ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
    }
    return false
}

Java

@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class)
Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        List\ filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA
                .filter(cameraProvider.getAvailableCameraInfos());
        if (!filteredCameraInfos.isEmpty()) {
            return Objects.equals(
                Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic(
                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL),
                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3);
        }
    }
    return false;
}

注意:如果创建的用例组合不兼容,则在首次调用 createCaptureSession() 时会抛出运行时错误。如果将其他用例添加到正在运行的会话中,可能需要进行重新配置,这可能会导致可见的故障。

权限

您的应用需要 CAMERA 权限。如需将图片保存到文件中,除非所用设备搭载 Android 10 或更高版本,否则应用还需要 WRITE_EXTERNAL_STORAGE 权限。

如需详细了解如何为应用配置权限,请参阅请求应用权限。

要求

CameraX 具有以下最低版本要求:

Android API 级别 21
Android 架构组件 1.1.1

对于能够感知生命周期的 Activity,请使用 FragmentActivity 或 AppCompatActivity。

声明依赖项

要添加 CameraX 的依赖项,您必须将 Google Maven 代码库添加到项目中。

打开项目的 settings.gradle 文件并添加 google() 代码库,如下所示:
Groovy

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

Kotlin

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

将以下内容添加到 Android 代码块的末尾:
Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

将以下内容添加到应用的每个模块的 build.gradle 文件中:
Groovy

dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.3.0-alpha04"
  // The following line is optional, as the core library is included indirectly by camera-camera2
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  // If you want to additionally use the CameraX Lifecycle library
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  // If you want to additionally use the CameraX VideoCapture library
  implementation "androidx.camera:camera-video:${camerax_version}"
  // If you want to additionally use the CameraX View class
  implementation "androidx.camera:camera-view:${camerax_version}"
  // If you want to additionally add CameraX ML Kit Vision Integration
  implementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
  // If you want to additionally use the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:${camerax_version}"
}

Kotlin

dependencies {
    // CameraX core library using the camera2 implementation
    val camerax_version = "1.3.0-alpha04"
    // The following line is optional, as the core library is included indirectly by camera-camera2
    implementation("androidx.camera:camera-core:${camerax_version}")
    implementation("androidx.camera:camera-camera2:${camerax_version}")
    // If you want to additionally use the CameraX Lifecycle library
    implementation("androidx.camera:camera-lifecycle:${camerax_version}")
    // If you want to additionally use the CameraX VideoCapture library
    implementation("androidx.camera:camera-video:${camerax_version}")
    // If you want to additionally use the CameraX View class
    implementation("androidx.camera:camera-view:${camerax_version}")
    // If you want to additionally add CameraX ML Kit Vision Integration
    implementation("androidx.camera:camera-mlkit-vision:${camerax_version}")
    // If you want to additionally use the CameraX Extensions library
    implementation("androidx.camera:camera-extensions:${camerax_version}")
}

如需详细了解如何配置应用以满足上述要求,请参阅声明依赖项。

CameraX 与 Camera2 的互操作性

CameraX 基于 Camera2 构建而成,并且 CameraX 提供了在 Camera2 实现中读取甚至写入属性的方式。如需了解完整详情,请参阅互操作性软件包。

如需详细了解 CameraX 如何配置 Camera2 属性,请使用 Camera2CameraInfo 读取底层 CameraCharacteristics。您还可以选择采用以下两个途径之一来写入底层 Camera2 属性:

使用 Camera2CameraControl,它让您可以在底层 CaptureRequest 上设置属性,例如自动对焦模式。

使用 Camera2Interop.Extender 扩展 CameraX UseCase。这样您就可以在 CaptureRequest 上设置属性,就像使用 Camera2CameraControl 一样。它还提供了一些额外的控件,例如设置数据流用例以根据您的使用场景优化相机。有关信息,请参阅使用数据流用例提高性能。

注意:在 CameraX 中,设置底层 Camera2 属性会被标记为“实验性”,因为 Google 希望开发者能了解其使用情况。您设置的值会替换 CameraX 所设置的任何值。我们建议您仅在绝对必要时执行此操作,也建议在您这一端进行其他测试。

以下代码示例使用数据流用例来优化视频通话。使用 Camera2CameraInfo 可提取视频通话流用例是否可用。然后,使用 Camera2Interop.Extender 设置底层数据流用例。
Kotlin

// Set underlying Camera2 stream use case to optimize for video calls.

val videoCallStreamId =
    CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong()

// Check available CameraInfos to find the first one that supports
// the video call stream use case.
val frontCameraInfo = cameraProvider.getAvailableCameraInfos()
    .first { cameraInfo ->
        val isVideoCallStreamingSupported = Camera2CameraInfo.from(cameraInfo)
            .getCameraCharacteristic(
                CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES
            )?.contains(videoCallStreamId)
        val isFrontFacing = (cameraInfo.getLensFacing() ==
                             CameraSelector.LENS_FACING_FRONT)
        (isVideoCallStreamingSupported == true) && isFrontFacing
    }

val cameraSelector = frontCameraInfo.cameraSelector

// Start with a Preview Builder.
val previewBuilder = Preview.Builder()
    .setTargetAspectRatio(screenAspectRatio)
    .setTargetRotation(rotation)

// Use Camera2Interop.Extender to set the video call stream use case.
Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId)

// Bind the Preview UseCase and the corresponding CameraSelector.
val preview = previewBuilder.build()
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)

Java

// Set underlying Camera2 stream use case to optimize for video calls.

Long videoCallStreamId =
    CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong();

// Check available CameraInfos to find the first one that supports
// the video call stream use case.
List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos();
CameraInfo frontCameraInfo = null;
for (cameraInfo in cameraInfos) {
    Long[] availableStreamUseCases = Camera2CameraInfo.from(cameraInfo)
        .getCameraCharacteristic(
            CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES
        );
    boolean isVideoCallStreamingSupported = Arrays.List(availableStreamUseCases)
                .contains(videoCallStreamId);
    boolean isFrontFacing = (cameraInfo.getLensFacing() ==
                             CameraSelector.LENS_FACING_FRONT);

    if (isVideoCallStreamingSupported && isFrontFacing) {
        frontCameraInfo = cameraInfo;
    }
}

if (frontCameraInfo == null) {
    // Handle case where video call streaming is not supported.
}

CameraSelector cameraSelector = frontCameraInfo.getCameraSelector();

// Start with a Preview Builder.
Preview.Builder previewBuilder = Preview.Builder()
    .setTargetAspectRatio(screenAspectRatio)
    .setTargetRotation(rotation);

// Use Camera2Interop.Extender to set the video call stream use case.
Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId);

// Bind the Preview UseCase and the corresponding CameraSelector.
Preview preview = previewBuilder.build()
Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)

其他资源

要详细了解 CameraX,请参阅下面列出的其他资源。

Codelab

CameraX 使用入门

代码示例

CameraX 示例应用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
# NDK Camera [![Build Status](https://travis-ci.org/luncliff/NdkCamera.svg?branch=master)](https://travis-ci.org/luncliff/NdkCamera) > If there is an issue with this library, please mail to [email protected] Simplified [Android Camera 2 API](https://www.youtube.com/watch?v=Bi4QjMfSOE0). Available for both Java/JNI. - API level: 24+ - NDK ### Reference - Personal Template Project: https://github.com/luncliff/Muffin - [API Reference](https://developer.android.com/ndk/reference/group/camera) - [Android Camera Overview](https://source.android.com/devices/camera) - Camera HAL3: https://source.android.com/devices/camera/camera3 - HAL Subsystem: https://source.android.com/devices/camera/camera3_requests_hal - Multi-Camera Support: https://source.android.com/devices/camera/multi-camera - Version Support: https://source.android.com/devices/camera/versioning - Android Media - https://source.android.com/devices/media/framework-hardening ## How to ### Build For **Windows** environment, latest [Android Studio](https://developer.android.com/studio/) is recommended. For **Linux/MacOS**, [Gradle 4.10.2](https://gradle.org/) will be enough. ```console $ git clone https://github.com/luncliff/NdkCamera $ cd ./NdkCamera $ gradle assemble # Build: libndk_camera.so & NdkCamera.aar ``` ### Test Connect your device and run the test with Gradle. Please reference the [test codes](./android/test/ndcam/). ```console $ gradle connectedAndroidTest # Run test ``` ### Use The following code shows working with `SurfaceView` class. ```java package dev.example; // ... import dev.ndcam.*; // Expect we already have a camera permission public class SurfaceDisplay implements SurfaceHolder.Callback { SurfaceView surfaceView; Surface surface; ndcam.Device camera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Load/Init library ndcam.CameraModel.Init(); surfaceView = findViewById(R.id.surfaceView); SurfaceHolder holder = surfaceView.getHolder(); holder.setFixedSize(1920, 1080); holder.setFormat(ImageFormat.YUV_420_888); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { // Get all devices in array form for(ndcam.Device device : ndcam.CameraModel.GetDevices()) if(device.facing() == CameraCharacteristics.LENS_FACING_BACK) camera = device; } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { // Make a repeating caputre request with surface surface = surfaceHolder.getSurface(); camera.repeat(surface); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { // No more capture if(camera != null) camera.stopRepeat(); } } ```
Android NDK开发是指利用NDK(Native Development Kit)将C/C++开发的代码编译成so库,然后通过JNI(Java Native Interface)让Java程序调用。在Android开发中,默认使用的是Android SDK进行Java语言的开发,而对于一些需要使用C/C++的高性能计算、底层操作或跨平台需求的场景,可以使用NDK进行开发。 在Android Studio中进行NDK开发相对于Eclipse来说更加方便,特别是在Android Studio 3.0及以上版本中,配置更加简化,并引入了CMake等工具,使得开发更加便捷。首先要进行NDK开发,需要配置环境,包括导入NDK、LLDB和CMake等工具。可以通过打开Android Studio的SDK Manager,选择SDK Tools,在其中选中相应的工具进行导入。 在项目的build.gradle文件中,可以配置一些NDK相关的参数,例如编译版本、ABI过滤器等。其中,可以通过externalNativeBuild配置CMake的相关设置,包括CMakeLists.txt文件的路径和版本号。此外,在sourceSets.main中还可以设置jniLibs.srcDirs,指定so库的位置。 在进行NDK开发时,可以在jni文件夹中编写C/C++代码,并通过JNI调用相关的函数。通过JNI接口,可以实现Java与C/C++之间的相互调用,从而实现跨语言的开发。 综上所述,Android NDK开发是指利用NDK将C/C++开发的代码编译成so库,并通过JNI实现与Java的相互调用。在Android Studio中进行NDK开发相对方便,可以通过配置环境和相应的参数来进行开发。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值