使用VS2019开发调试Android动态库

news2024/11/16 6:04:27

1. 环境准备

1.1 安装JDK:jdk1.8.0_112

1.2 安装Android SDK

SDK可以安装指定的platforms和ndk-bundle。为了兼容性考虑,单独安装了版本比较老的android-ndk-r10b

1.3 安装VS2019

安装VS2019并选择:使用C++的移动开发。

1.4 连接开发手机

使用USB数据线连接开发手机并打开开发手机的USB调试选项。

2. 创建Android动态库工程

2.1 创建新项目

启动VS2019,选择创建新项目

2.2 选择项目类型

下拉框选择C++、Android,列表选择动态共享库(Android),单击下一

2.3 填写项目属性

填写项目名称:MyTestSo,选择创建位置,单击创

2.4 项目创建完成

3. 创建动态库测试项目

3.1 新建Android项目

在解决方案上单击鼠标右键,选择弹出菜单中的添加->新建项目菜单项。

3.2 选择项目类型

下拉框选择C++、Android,列表选择Native-Activity应用程序(Android),单击下一步

3.3 填写项目属性

填写项目名称:Test,单击创建

 

3.4 项目创建完成

 3.5 ​​​​​​​添加引用

在左侧Test.NativeActivity项目下的引用上单击鼠标右键,选择弹出菜单:添加引用(R)…

选中MyTestSo,单击确定完成设置。

  1. 4. 设置IDE属性

 选择VS2019菜单项:工具 -> 选项,打开选项设置页面。

选择跨平台 –> C++ -> Android,填写右边的开发工具目录。

  1. 5. 设置项目属性

 直接编译创建出来的项目会出现一些如下所示的错误:

需要设置MyTestSo项目和Test.NativeActivity两个项目的编译属性,以下以MyTestSo项目为例。

打开MytestSo项目属性,选择左侧常规,修改右边的平台工具集为:GCC 4.9,目标API级别为android-L。

  1. 6. 编译运行

    6.1 修改动态库项目代码

在MyTestSo.cpp源码文件中增加测试函数test,代码如下:

   

void test()
{
	LOGI("Hello World From MyTestSo");
}

6.2 ​​​​​​​修改测试项目代码

在main.cpp源码文件中调用测试函数test,代码如下:

extern "C" void test();

test();

 ​​​​​​​6.3 编译运行项目

设置Test.Packaging项目为启动项目,选择编译并运行Test.Packaging项目,查看Logcat输出日志。

项目在有些低版本Android平台上运行可能会崩溃,解决方案参考第7节。

6.4 调试代码

在main.cpp或者MyTestSo.cpp中设置好断点,调试启动Test.Packaging项目,将会在设置的断点处中断,效果如下图所示:

7. 崩溃问题解决

项目在有些低版本Android平台上运行可能会崩溃,出现如下错误:

原因在于libTest.so库依赖了libMyTestSo.so库,项目在运行时加载libTest.so库之前并没有加载libMyTestSo.so库,从而导致了崩溃。解决方案为自定义项目启动类,在启动类里加载so库。

​​​​​​​7.1 自定义项目启动类

在项目Test.Packaging中添加目录结构:src/com/mytest,在mytest目录下创建java源文件MyTestActivity.java,内容如下:

package com.mytest;

import android.app.NativeActivity;

public class MyTestActivity extends NativeActivity
{
    static
    {
	    System.loadLibrary("MyTestSo"); 
        System.loadLibrary("Test"); 
	}
}

 

7.2 修改AndroidManifest.xml

打开AndroidManifest.xml编辑内容,

  • android:hasCode 属性修改为:true
  • android:name 属性修改为:com.mytest.MyTestActivity

7.3 重新编译运行项目

附录:使用jar包

原文链接:https://retroscience.net/visual-studio-android-ndk-jar-files.html

Android NDK, JAR files, JNI, and Visual Studio

For those of you who don’t know, I have been a Visual Studio user for a long time now, amoung other forms of IDEs I’ve used Visual Studio the most. Something else I also love to use is the C programming language (I wish VS was more up to date for C but it’s good enough). One of the things you can do is develop for Android using NDK and Visual Studio which works fairly well, even though it is using Ant instead of Gradle, I find that it has suited all of my needs so far. That being said, I’m going to drop some tips here on how to make the development process a bit more friendly to be able to interact via JNI and native code.

Note: I am assuming you’ve setup Visual Studio and installed native android development

Update Ant

If you’ve installed Android native development through Visual Studio, you should have everything you need (NDK & SDK) inside of the C:/Microsoft folder. Something we need to do is tell the Ant build system to use a more modern version of JDK (OpenJDK) for building java code. To do this, open the C:/Microsoft/AndroidSDK/25/tools/ant/build.xml file in a text editor and locate the line that starts with <property name="java.target". Change the value of this to 1.7. Do the same thing for <property name="java.source". At this point you should see something like the following:

<!-- compilation options -->
<property name="java.encoding" value="UTF-8" />
<property name="java.target" value="1.7" />
<property name="java.source" value="1.7" />
<property name="java.compilerargs" value="" />
<property name="java.compiler.classpath" value="" />

project.properties

My project properties file in the .sln looks like the following:

# Project target
target=$(androidapilevel)
# Provide path to the directory where prebuilt external jar files are by setting jar.libs.dir=
jar.libs.dir=libs

AndroidManifest.xlm

Since we are going to be writing .jar files and possibly loading in external libraries at runtime, we will need to setup our project to have our own custom native activity code. Inside the AndroidManifest.xlm file you will need to find the android:hasCode="" value in the <application> tag and set it’s value to true. It should look similar to the following:

<application android:label="@string/app_name" android:hasCode="true">
	<!-- ... -->
</application>

Next we will want to set the <activity android:name="" value to our package and activity name that we will be creating. So if your activity class name is going to be FancyActivity then you should have something similar to the following:

<activity android:name="com.PackageName.FancyActivity" android:label="@string/app_name">
	<!-- ... -->
</activity>

Creating our custom activity

Since our full class path will be com.PackageName.FancyActivity we will need to create a few folders inside of our *.Packaging project in Visual studio. Create a folder path named src/com/PackageName/. Next create a file inside of the PackageName folder named FancyActivity.java. Below is the code you should have inside of FancyActivity.java:

package com.PackageName;
import android.app.NativeActivity;
public class FancyActivity extends NativeActivity
{
	static
	{
		//System.loadLibrary("other_lib");
	}
}

Notice the commented out line System.loadLibrary. You can call this as many times as needed, but all you need to do is replace "other_lib" with the name of your library, like System.loadLibrary("fmod"); or something similar. At this point you should be able to build without any issues.

Pro tip: You should always add System.loadLibrary("ProjectName"); where ProjectName is the name of the .so file that is generated for your NDK project build. This will allow you to call native functions from within your Java code (great for callbacks and the like).

Custom JAR files

Now that we’ve setup our activity to better interact with JNI and load other libraries, we are going to look at how to add our own .jar files and access the types within them from native code.

Building .jar files

Make sure and compile your code with -source 1.7 -target 1.7 so that it is matching Ant’s versions we setup earlier. After you’ve built your .class files, ensure your folder structure is correct as it relates to the package path. If your package path for your class(es) is package com.PackageName; then you should have the .class file within a folder structure com/PackageName/*.class. When you build your .jar file it should be for the whole folder structure.

Including .jar files in project

Now that you have your .jar file, you should create a folder named libs in your *.Packaging project. Place your .jar file into this folder and make sure to right click it and select Include In Project.

Accessing your code inside the .jar file

Lets assume for this part you’ve created a class named Dummy with a function that has the signature void SayHi(string name) which will print out “Hello, %s!” (%s = name input string of function). We will use JNI to access your code and invoke your method. Below is the code we will use to call our function. You can place it directly inside of your void android_main(struct android_app* state) function:

JNIEnv* env = NULL;
const ANativeActivity* activity = state->activity;
(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);

jobject jobj = activity->clazz;
jclass clazz = (*env)->GetObjectClass(env, jobj);
jmethodID getClassLoader = (*env)->GetMethodID(env, clazz, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = (*env)->CallObjectMethod(env, jobj, getClassLoader);
jclass classLoader = (*env)->FindClass(env, "java/lang/ClassLoader");
jmethodID findClass = (*env)->GetMethodID(env, classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
jstring strClassName = (*env)->NewStringUTF(env, "com.PackageName.Dummy");
jclass fancyActivityClass = (jclass)((*env)->CallObjectMethod(env, cls, findClass, strClassName));
(*env)->DeleteLocalRef(env, strClassName);
jmethodID sayHi = (*env)->GetStaticMethodID(env, fancyActivityClass, "SayHi", "(Ljava/lang/String;)V");
jstring words = (*env)->NewStringUTF(env, "Brent");
(*env)->CallStaticVoidMethod(env, fancyActivityClass, sayHi, words);
(*env)->DeleteLocalRef(env, words);

​​​​​​​Now those who have had a little exposure with JNI might say “Can’t we just use the (*env)->FindClass method? While this may be true for normal Android built in classes, it is not true for our own custom class. The reasoning is that JNI can only look through what is currently on the stack, and believe it or not, even though our FancyActivity is running our code, it isn’t on the stack so we can’t even find it. So what we need to do is get the current activity, then find a method on it called getClassLoader. Once we have this function, we are free to load any class from anywhere that is loaded, even inside our .jar code.

Hope this helps people who are having trouble. It tooke me a full day to figure out all of this stuff because there isn’t anything straight forward on the internet, I had to dig really deep to find all the pieces to put this together!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/79199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+Mysql实现(web)大型企业管理系统【100010019】

第一章 系统概述 包括用户管理、权限管理、软件项目管理、软件模块管理、测试用例管理、测试任务分配、bug管理等功能。实现公司不同部门间团队协作&#xff0c;管理人员也能够更加有效的把控系统开发的进度。 本实验综合应用JavaWeb编程中的Servlet&#xff0c;JSP&#xff…

spring——Spring自动装配(基于注解)——前提了解——Spring的@Autowired注解为什么用在接口上 (转载)...

大家都知道Service注入的是实现类serviceImpl&#xff0c;那使用时怎么能获取到接口&#xff0c;而且还能调用到实现类的方法。 接口&#xff1a; public interface TestService{ public String test(); }实现类&#xff1a; Service public class TestServiceImpl imp…

Netty_04_消息协议设计与实战(实践类)

文章目录一、前言二、整体运行&#xff1a;先启动服务端&#xff0c;然后启动客户端&#xff0c;发送三条消息三、客户端和服务端3.1 客户端(重要)3.2 服务端(重要)3.3 编码和解码(了解即可)四、尾声一、前言 源码下载&#xff1a;https://www.syjshare.com/res/XEE10LTG 二、…

【Linux修炼】10.进程地址空间

每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 进程地址空间本节目标1. 回顾C/C地址空间1.1 提出问题1.2 见问题产生的现象1.3 解释现象2. 虚拟地址空间2.1 感性理解虚拟地址空间 2.2 如何“画饼”2.3 地址空间的区域划分3. 进程地址空间与内存的关系3.1 虚拟地址和物理…

LabVIEW编程LabVIEW开发 ADAM-4056 DO模块例程与相关资料

LabVIEW编程LabVIEW开发 ADAM-4056 DO模块例程与相关资料 ​ADAM-4056SO是具有12通道自源型携带Modbus协议隔离数字输出模块。具有如下特点&#xff1a; ADO源电源故障检测 输入/输出类型&#xff1a;源式输出 12通道 数字输出&#xff1a;VCC&#xff1a; 1~35伏直流电&a…

基于Java+Mysql实现(WEB)宿舍管理系统【100010016】

数据库实践课程之宿舍管理系统 一、系统需求分析 1.1 系统描述 随着社会的发展以及教育水平的提高&#xff0c;当今社会在校生的数量越来越庞大&#xff0c;使用传统的方式对学生的信息进行管理效率非常低下。在互联网技术高度发达的今天&#xff0c;使用数据库技术对学生的…

Go 实现希尔排序算法及图解

耐心和持久胜过激烈和狂热。 哈喽大家好&#xff0c;我是陈明勇&#xff0c;今天分享的内容是使用 Go 实现希尔排序算法。如果本文对你有帮助&#xff0c;不妨点个赞&#xff0c;如果你是 Go 语言初学者&#xff0c;不妨点个关注&#xff0c;一起成长一起进步&#xff0c;如果本…

游戏开发51课 性能优化9

4.5 光照模型&#xff08;Lighting/Illumination Model&#xff09; 4.5.1 Flat Shading&#xff08;平面着色&#xff09; 根据表面法向量计算光照&#xff0c;并应用到整个面片上。速度最快&#xff0c;效果最差&#xff0c;容易暴露物体的多边形本质&#xff08;下图&…

微服务框架 SpringCloud微服务架构 29 ES 集群 29.4 分布式新增和查询流程

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构29 ES 集群29.4 分布式新增和查询流程29.4.1 ES集群的分布式存储29.4.2 总…

鸿蒙手机卸载内置应用 adb连接

鸿蒙手机傻瓜式卸载内置应用 adb连接**傻瓜式删除鸿蒙系统内置应用&#xff0c;自己亲测有效。**准备物品准备软件准备工作教程开始&#xff1a;第一步第二步完成包名列表一般软件谷歌服务格外的注意连接错误**鸣谢**傻瓜式删除鸿蒙系统内置应用&#xff0c;自己亲测有效。 准…

缓存数据丢了,原来是Redis持久化没玩明白

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…

Windows下MySQL5.5升级5.7(或直接安装MySQL5.7)

Windows下MySQL5.5升级5.7&#xff08;或直接安装MySQL5.7&#xff09; 1、关闭MySQL服务&#xff1a; Ctrl shift Esc找到服务&#xff0c;找到下面的MySQL服务&#xff0c;停止服务。 2、卸载程序&#xff1a; 控制面板中卸载mysql5.5。 3、删除mysql5.5的安装目录及注…

Linux文件操作

文章目录前言什么是文件文件操作C语言文件操作接口文件操作系统调用接口文件描述符如何理解FILE和文件描述符的关系前言 本文主要介绍的是Linux系统下的文件操作和Linux的文件系统的机制&#xff0c;希望能够通过本文来增加读者对于文件操作的基本使用和理解。以及了解Linux系…

【大数据入门核心技术-Ambari】(一)Ambari介绍

一、什么是Ambari Apache Ambari是一种基于Web的工具&#xff0c;支持Apache Hadoop集群的供应、管理和监控。Ambari已支持大多数Hadoop组件&#xff0c;包括HDFS、MapReduce、Hive、Pig、 Hbase、Zookeeper、Sqoop和Hcatalog等。 Apache Ambari 支持HDFS、MapReduce、Hive、Pi…

C语言宏和预处理

C语言宏和预处理【1】include【2】【#pragma】【3】C #include【4】# 和 ## 操作符【5】宏替换【6】#line【7】#error【8】#undef【9】源码【10】结果【1】include #include本命令包含一个文件并在当前位置插入.一般尖括号意味着在标准库目录中搜索, #include “filename” 引…

【C语言与汇编】简单学学C到汇编代码

C语言与汇编 部分过程可参考C primer plus 本书余下的篇幅讨论源代码文件中的内容&#xff1b;本节讨论创建源代码文 件的技巧。有些C实现&#xff08;如Microsoft Visual C、Embarcadero C Builder、Apple Xcode、Open Watcom C、Digital Mars C和Freescale CodeWarrior&…

精品基于SSM的民宿预订管理系统

《民宿预订管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 使用技术&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;my…

云原生事件驱动框架(KnativeEventing)

事件驱动是指事件在持续事务管理过程中&#xff0c;进行决策的一种策略。可以通过调动可用资源执行相关任务&#xff0c;从而解决不断出现的问题。通俗地说是当用户触发使用行为时对用户行为的响应。在 Serverless 场景下&#xff0c;事件驱动完美符合其设计初衷之一&#xff1…

基于xv6的Copy-On-Write

为什么需要写时拷贝呢&#xff1f; 当 shell执行指令的时候会 fork()&#xff0c;而这个 fork()出来的进程首先会调用的就是 exec来执行对应的命令&#xff0c;如果我们将 fork()创建的进程对地址空间进行了完整的拷贝,那将是一个巨大的消耗 因为在实际应用中&#xff0c;for…

SSM项目整合

文章目录1. 导入依赖2. 配置web.xml文件3. 编写springmvc.xml配置文件4. 编写spring.xml配置文件5. 编写项目整体业务逻辑6. 开发过程中常见状态码错误1. 导入依赖 在整合SSM项目时&#xff0c;需要导入以下依赖 Spring 相关依赖 &#xff08;springmvc相关、事务相关、spring…