C# Java间进行RSA加密解密交互

这里,讲一下RSA算法加解密在C#Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了。

首先,介绍一下写这代码的目的:完成webService验证问题,服务器端采用C#开发,客户端采用Java开发。服务器端给客户端提供公钥,已进行数据加密,客户端加密后提数据提交给服务器,服务器用私钥对数据解密,进行验证。 

这里遇到的主要问题是C# RSACryptoServiceProvider类产生的公钥、私钥都是xml字符串数据,而java RSA算法要求的 Modulus、Exponent都是BigInteger类型,两者间的转换才是问题所在。 

关于Java 和 C#各自独立的进行RSA加密解密,大家可以看整两篇文章,java RSA加密解密实现() 和 C#RSA加密解密和签名与验证的实现。 

接下来讲一下实现步骤:

首先由C# RSACryptoServiceProvider类生成公钥、私钥

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>   
  2.        /// 生成公钥、私钥   
  3.        /// </summary>   
  4.        /// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>   
  5.        public Dictionary<stringstring> createKeyPair()  
  6.        {  
  7.            Dictionary<stringstring> keyPair = new Dictionary<stringstring>();  
  8.            RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);  
  9.            keyPair.Add("PUBLIC", provider.ToXmlString(false));  
  10.            keyPair.Add("PRIVATE", provider.ToXmlString(true));  
  11.            return keyPair;  
  12.        }  
[csharp] view plain copy
  1. /// <summary>  
  2.        /// 生成公钥、私钥  
  3.        /// </summary>  
  4.        /// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>  
  5.        public Dictionary<stringstring> createKeyPair()  
  6.        {  
  7.            Dictionary<stringstring> keyPair = new Dictionary<stringstring>();  
  8.            RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);  
  9.            keyPair.Add("PUBLIC", provider.ToXmlString(false));  
  10.            keyPair.Add("PRIVATE", provider.ToXmlString(true));  
  11.            return keyPair;  
  12.        }  

如此处生成的公钥为

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <RSAKeyValue>  
  2.     <Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=  
  3.     </Modulus>  
  4.     <Exponent>AQAB</Exponent>  
  5. </RSAKeyValue>  
[html] view plain copy
  1. <RSAKeyValue>  
  2.     <Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=  
  3.     </Modulus>  
  4.     <Exponent>AQAB</Exponent>  
  5. </RSAKeyValue>  
在客户端(Java)对C#提供的公钥提取Modulus和Exponent
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * 返回包含模数modulus和指数exponent的haspMap 
  3.      * @return 
  4.      * @throws MalformedURLException 
  5.      * @throws DocumentException 
  6.      */  
  7.     public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{  
  8.         HashMap<String ,String> map = new HashMap<String, String>();   
  9.         Document doc = DocumentHelper.parseText(xmlPublicKey);  
  10.         String mudulus = (String) doc.getRootElement().element("Modulus").getData();  
  11.         String exponent = (String) doc.getRootElement().element("Exponent").getData();  
  12.         map.put("mudulus", mudulus);  
  13.         map.put("exponent", exponent);  
  14.         return map;  
  15.     }  
[java] view plain copy
  1. /** 
  2.      * 返回包含模数modulus和指数exponent的haspMap 
  3.      * @return 
  4.      * @throws MalformedURLException 
  5.      * @throws DocumentException 
  6.      */  
  7.     public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{  
  8.         HashMap<String ,String> map = new HashMap<String, String>();   
  9.         Document doc = DocumentHelper.parseText(xmlPublicKey);  
  10.         String mudulus = (String) doc.getRootElement().element("Modulus").getData();  
  11.         String exponent = (String) doc.getRootElement().element("Exponent").getData();  
  12.         map.put("mudulus", mudulus);  
  13.         map.put("exponent", exponent);  
  14.         return map;  
  15.     }  

用ModulusExponent产生公钥RSAPublicKeyjava

这里有个关键步骤先对MudolusExponent进行Base64解码,这个是由于C#生成的密钥对,其参数已经过Base64编码成String类型,而java RSA参数是未经base64编码的byte[]类型

至于Base64编码、解码方法,参考这篇文章,java 编码和解码,想详细。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static byte[] decodeBase64(String input) throws Exception{    
  2.         Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");    
  3.         Method mainMethod= clazz.getMethod("decode", String.class);    
  4.         mainMethod.setAccessible(true);    
  5.          Object retObj=mainMethod.invoke(null, input);    
  6.          return (byte[])retObj;    
  7.     }  
  8.       
  9.     /** 
  10.      * 返回RSA公钥 
  11.      * @param modules 
  12.      * @param exponent 
  13.      * @return 
  14.      */  
  15.     public static PublicKey getPublicKey(String modulus, String exponent){  
  16.         try {   
  17.             byte[] m = decodeBase64(modulus);  
  18.             byte[] e = decodeBase64(exponent);  
  19.             BigInteger b1 = new BigInteger(1,m);    
  20.             BigInteger b2 = new BigInteger(1,e);    
  21.             KeyFactory keyFactory = KeyFactory.getInstance("RSA");    
  22.             RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);    
  23.             return (RSAPublicKey) keyFactory.generatePublic(keySpec);    
  24.         } catch (Exception e) {    
  25.             e.printStackTrace();    
  26.             return null;    
  27.         }     
  28.     }  
[java] view plain copy
  1. public static byte[] decodeBase64(String input) throws Exception{    
  2.         Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");    
  3.         Method mainMethod= clazz.getMethod("decode", String.class);    
  4.         mainMethod.setAccessible(true);    
  5.          Object retObj=mainMethod.invoke(null, input);    
  6.          return (byte[])retObj;    
  7.     }  
  8.       
  9.     /** 
  10.      * 返回RSA公钥 
  11.      * @param modules 
  12.      * @param exponent 
  13.      * @return 
  14.      */  
  15.     public static PublicKey getPublicKey(String modulus, String exponent){  
  16.         try {   
  17.             byte[] m = decodeBase64(modulus);  
  18.             byte[] e = decodeBase64(exponent);  
  19.             BigInteger b1 = new BigInteger(1,m);    
  20.             BigInteger b2 = new BigInteger(1,e);    
  21.             KeyFactory keyFactory = KeyFactory.getInstance("RSA");    
  22.             RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);    
  23.             return (RSAPublicKey) keyFactory.generatePublic(keySpec);    
  24.         } catch (Exception e) {    
  25.             e.printStackTrace();    
  26.             return null;    
  27.         }     
  28.     }  

获得公钥后就可以进行RSA加密处理了,这里还有一点需要提的是,RSA加密解密都有最大长度限制,加密最大长度为117字节,解密最大长度是128字节,此外,此处加密得到的数据是经过Base64编码处理的

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static String encrypt(byte[] source, PublicKey publicKey) throws Exception   {  
  2.         String encryptData ="";  
  3.         try {  
  4.             Cipher cipher = Cipher.getInstance("RSA");  
  5.             cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  6.             int length = source.length;  
  7.             int offset = 0;  
  8.             byte[] cache;  
  9.             ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
  10.             int i = 0;  
  11.             while(length - offset > 0){  
  12.                 if(length - offset > MAXENCRYPTSIZE){  
  13.                     cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);  
  14.                 }else{  
  15.                     cache = cipher.doFinal(source, offset, length - offset);  
  16.                 }  
  17.                 outStream.write(cache, 0, cache.length);  
  18.                 i++;  
  19.                 offset = i * MAXENCRYPTSIZE;  
  20.             }  
  21.             return encodeBase64(outStream.toByteArray());  
  22.         } catch (NoSuchAlgorithmException e) {  
  23.             e.printStackTrace();  
  24.         } catch (NoSuchPaddingException e) {  
  25.             e.printStackTrace();  
  26.         } catch (InvalidKeyException e) {  
  27.             e.printStackTrace();  
  28.         } catch (IllegalBlockSizeException e) {  
  29.             e.printStackTrace();  
  30.         } catch (BadPaddingException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         return encryptData;       
  34.     }  
[java] view plain copy
  1. public static String encrypt(byte[] source, PublicKey publicKey) throws Exception   {  
  2.         String encryptData ="";  
  3.         try {  
  4.             Cipher cipher = Cipher.getInstance("RSA");  
  5.             cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  6.             int length = source.length;  
  7.             int offset = 0;  
  8.             byte[] cache;  
  9.             ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
  10.             int i = 0;  
  11.             while(length - offset > 0){  
  12.                 if(length - offset > MAXENCRYPTSIZE){  
  13.                     cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);  
  14.                 }else{  
  15.                     cache = cipher.doFinal(source, offset, length - offset);  
  16.                 }  
  17.                 outStream.write(cache, 0, cache.length);  
  18.                 i++;  
  19.                 offset = i * MAXENCRYPTSIZE;  
  20.             }  
  21.             return encodeBase64(outStream.toByteArray());  
  22.         } catch (NoSuchAlgorithmException e) {  
  23.             e.printStackTrace();  
  24.         } catch (NoSuchPaddingException e) {  
  25.             e.printStackTrace();  
  26.         } catch (InvalidKeyException e) {  
  27.             e.printStackTrace();  
  28.         } catch (IllegalBlockSizeException e) {  
  29.             e.printStackTrace();  
  30.         } catch (BadPaddingException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         return encryptData;       
  34.     }  

加密后的数据提交给C#服务器端进行解密,当然,这里也要注意最大长度限制问题

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>   
  2.         /// RSA解密   
  3.         /// </summary>   
  4.         /// <param name="encryptData">经过Base64编码的密文</param>   
  5.         /// <param name="privateKey">私钥</param>   
  6.         /// <returns>RSA解密后的数据</returns>   
  7.         public static string decrypt(string encryptData, string privateKey)  
  8.         {  
  9.             string decryptData = "";  
  10.             try  
  11.             {  
  12.                 RSACryptoServiceProvider provider = new RSACryptoServiceProvider();  
  13.                 provider.FromXmlString(privateKey);  
  14.                 byte[] bEncrypt = Convert.FromBase64String(encryptData);                  
  15.                 int length = bEncrypt.Length;  
  16.                 int offset = 0;  
  17.                 string cache ;  
  18.                 int i = 0;  
  19.                 while (length - offset > 0)  
  20.                 {  
  21.                     if (length - offset > MAXDECRYPTSIZE)  
  22.                     {  
  23.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));  
  24.                     }  
  25.                     else  
  26.                     {  
  27.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));  
  28.                     }  
  29.                     decryptData += cache;  
  30.                     i++;  
  31.                     offset = i*MAXDECRYPTSIZE;  
  32.                 }  
  33.             }  
  34.             catch(Exception e)  
  35.             {  
  36.                 throw e;  
  37.             }  
  38.             return decryptData;  
  39.         }  
  40.   
  41.         /// <summary>   
  42.         /// 截取字节数组部分字节   
  43.         /// </summary>   
  44.         /// <param name="input"></param>   
  45.         /// <param name="offset">起始偏移位</param>   
  46.         /// <param name="length">截取长度</param>   
  47.         /// <returns></returns>   
  48.         private static byte[] getSplit(byte[] input, int offset, int length)  
  49.         {   
  50.             byte[] output = new byte[length];  
  51.             for (int i = offset; i < offset + length; i++)  
  52.             {  
  53.                 output[i - offset] = input[i];  
  54.             }  
  55.             return output;  
  56.         }  
[csharp] view plain copy
  1. /// <summary>  
  2.         /// RSA解密  
  3.         /// </summary>  
  4.         /// <param name="encryptData">经过Base64编码的密文</param>  
  5.         /// <param name="privateKey">私钥</param>  
  6.         /// <returns>RSA解密后的数据</returns>  
  7.         public static string decrypt(string encryptData, string privateKey)  
  8.         {  
  9.             string decryptData = "";  
  10.             try  
  11.             {  
  12.                 RSACryptoServiceProvider provider = new RSACryptoServiceProvider();  
  13.                 provider.FromXmlString(privateKey);  
  14.                 byte[] bEncrypt = Convert.FromBase64String(encryptData);                  
  15.                 int length = bEncrypt.Length;  
  16.                 int offset = 0;  
  17.                 string cache ;  
  18.                 int i = 0;  
  19.                 while (length - offset > 0)  
  20.                 {  
  21.                     if (length - offset > MAXDECRYPTSIZE)  
  22.                     {  
  23.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));  
  24.                     }  
  25.                     else  
  26.                     {  
  27.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));  
  28.                     }  
  29.                     decryptData += cache;  
  30.                     i++;  
  31.                     offset = i*MAXDECRYPTSIZE;  
  32.                 }  
  33.             }  
  34.             catch(Exception e)  
  35.             {  
  36.                 throw e;  
  37.             }  
  38.             return decryptData;  
  39.         }  
  40.   
  41.         /// <summary>  
  42.         /// 截取字节数组部分字节  
  43.         /// </summary>  
  44.         /// <param name="input"></param>  
  45.         /// <param name="offset">起始偏移位</param>  
  46.         /// <param name="length">截取长度</param>  
  47.         /// <returns></returns>  
  48.         private static byte[] getSplit(byte[] input, int offset, int length)  
  49.         {   
  50.             byte[] output = new byte[length];  
  51.             for (int i = offset; i < offset + length; i++)  
  52.             {  
  53.                 output[i - offset] = input[i];  
  54.             }  
  55.             return output;  
  56.         }  
这样,就顺利完成了。

经过测试,这样做的确得到了正确的结果。

若是有什么地方有问题,还望大家指正!

----------------------------------------------------------------------------------------

C# Java间进行RSA加密解密交互(二)

C# Java间进行RSA加密解密交互(三)

 

转自:http://blog.csdn.net/dslinmy/article/details/37362661

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

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

相关文章

【Microstation】三维建模基础及软件入门到精通实验教程目录

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 MicroStation是一款非常不错的二维和三维设计软件&#xff0c;由奔特力&#xff08;Bentley&#xff09;工程软件系统有限公司开发的一款软件。在CAD设计上该软件是和AutoCAD是齐名的软件&#xff0c;其专用的文件格式是…

无代码iVX编程实现简单魂斗罗

首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后咱们选择2D游戏类型制作一个简单魂斗罗游戏&#xff1a; 随后咱们开始创建一个物理世界&#xff0c;不并且在物理世界之下创建一个一个图片添加物体属性&#xff0c;在物体属性中更改对应的属性内容&am…

【ArcGIS遇上Python】ArcGIS Python批处理入门到精通实用教程目录

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 Python语言是目前很火热的语言&#xff0c;极大的促进了人工智能发展。你知道在ArcGIS中也会有python的身影吗&#xff1f;事实上&#xff0c;在ArcGIS中使用Python会起到事半功倍的效果&#xff0c;大大提高工作效率&am…

Android使用C/C++来保存密钥

Android使用C/C来保存密钥本文主要介绍如何通过native方法调用取出密钥&#xff0c;以替代原本直接写在Java中&#xff0c;或写在gradle脚本中的不安全方式。为什么要这么做 如果需要在本地存储一个密钥串&#xff0c;典型的方式有 1. 直接写在java source code中 2. 写在gradl…

无代码iVX编程实现简单跳跃超级玛丽游戏

首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后咱们选择2D游戏类型制作一个简单跳跃游戏&#xff1a; 接下来创建几个图片&#xff0c;并且添加物体&#xff0c;如图所示&#xff1a; 在此需要更改对应称重地面的阻尼值&#xff0c;让其能够缓慢降落…

【三维激光扫描】实验01:环境搭建CAD2014+StonexSiScan软件安装

目 录 一、CAD2014简体中文版安装1. 安装过程2. 激活过程二、Si-Scan安装1. 主程序安装2. 驱动安装一、CAD2014简体中文版安装 1. 安装过程 双击安装包:AutoCAD_2014_Simplified_Chinese_Win_64bit_dlm.sfx.exe,进行自解压。 解压完成后,如下图所示,点击【安装】。 接受许…

C# 11 新特性:原始字符串

之前我们经常需要使用 string 类型定义字符串文本&#xff0c;字符串文本用一对双引号括起来表示&#xff1a;var str "Hello MyIO";字符串可包含任何字符文本&#xff0c;但是有些字符需要转义才能表示&#xff0c;比如双引号要转义成\"&#xff1a;var str …

bzoj1011

因为允许5%的误差。。所以把&#xff1e;一定长度的一段看成一段近似计算就行了。。 1 #include<cstdio>2 #include<cstdlib>3 #include<cstring>4 #include<ctime>5 #include<cmath>6 #include<iostream>7 #include<algorithm>8 #i…

一名全栈工程师的必备“百宝箱”

摘要&#xff1a;全栈工程师&#xff0c;也叫全端工程师&#xff0c;是指掌握多种技能&#xff0c;并能利用多种技能独立完成产品的人。全栈工程师熟悉多种开发语言&#xff0c;同时具备前端和后台开发能力&#xff0c;从需求分析&#xff0c;原型设计到产品开发&#xff0c;测…

为VMware虚拟主机添加新磁盘

轨迹: 关闭VMware虚拟主机 ---> 虚拟机 ---> 设置 ---> 硬件 ---> 硬盘 ---> 添加 ---> (弹出添加硬件向导)硬盘 ---> 磁盘类型 ---> 选择磁盘 ---> 指定磁盘容量(最好选择“将虚拟磁盘存储为单个文件”) ---> 指定磁盘文件 ---> 点击“完成…

【ArcGIS风暴】全站仪、RTK测量坐标数据在CASS和ArcGIS中展点的区别和联系(带数据)

ArcGIS展经纬度点完整教程:【ArcGIS风暴】ArcGIS 10.2导入Excel数据X、Y坐标(经纬度、平面坐标),生成Shapefile点数据图层 目录 1. CASS展点操作步骤2. ArcGIS展点操作步骤3. 案例数据下载RTK或全站仪地面实测的三维坐标数据文件一般包括点号,编码,东坐标,北坐标,高程等…

php一篇文零基础到制作在线图片编辑网站赚钱(gif压缩、九宫格裁剪、等比裁剪、大小变换)【php华为云实战】

注意本篇文适用于&#xff1a; 零基础小白想要了解一下php开发或者网站开发的同学&#xff08;但是注意&#xff0c;零基础你可以通过本篇完成&#xff0c;但是由于是速成会有一些难度&#xff0c;本篇内容由于是速成&#xff0c;有一些额外知识点&#xff0c;不会可以来问我1…

MAUI 自定义绘图入门

在2022的5月份&#xff0c;某软正式发布了 MAUI 跨平台 UI 框架。我本来想着趁六一儿童节放假来写几篇关于 MAUI 入门的博客&#xff0c;可惜发现我不擅长写很入门的博客。再加上 MAUI 似乎是为了赶发布日期而发布&#xff0c;只能勉强说能开发了&#xff0c;能用了。于是我就来…

【三维激光扫描】实验02:StonexSiScan新建项目、加载点云数据

文章目录 1. 新建工程2. 打开工程3. 加载点云1. 新建工程 打开StonexSiScan点云后处理软件,点击【新建】按钮。 选择工程存放路径,输入工程名称。 2. 打开工程 点击【打开】按钮。

eBPF 在云原生环境中的应用

端午假期&#xff0c;我翻译了 OReilly 的报告《什么是 eBPF》&#xff0c;其中我觉得第五章「云原生环境中的 eBPF」解答了我心中的很多疑惑&#xff0c;比较不错&#xff0c;分享给大家。下面是第五章译文。《什么是 eBPF》中文版封面近年来&#xff0c;云原生应用已呈指数级…

使用HtmlAgilityPack抓取网页数据

XPath路径表达式&#xff0c;主要是对XML文档中的节点进行搜索&#xff0c;通过XPath表达式可以对XML文档中的节点位置进行快速定位和访问&#xff0c;html也是也是一种类似于xml的标记语言&#xff0c;但是语法没有那么严谨&#xff0c;在codeplex里有一个开源项目HtmlAgility…

企业有了程序员为什么还要用 低代码/无代码

一、备受“争议”的无代码/低代码开发 在看这篇内容时&#xff0c;我们要知道&#xff0c;技术无时无刻不在进行发展&#xff0c;IT技术更是如此&#xff0c;快速的技术更新使得程序员在进行应用开发时效率更高&#xff1b;我记得在十多年前&#xff0c;开发一个普通的 HTML 页…

【三维激光扫描技术】原理、方法及实验图文教程目录

《三维激光扫描技术》专栏讲述目前最先进、最流行的三维激光技术&#xff0c;包括三维激光扫描技术原理&#xff0c;三维测距原理&#xff0c;国内外三维扫描设备&#xff0c;点云特点&#xff0c;三维建模&#xff0c;三维激光优势、应用领域&#xff0c;应用技术案例等。 文章…

求最长回文串

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 转载于:https://www.cnblogs.com/yangscode/p/5017527.html

实训三(cocos2dx 3.x 打包apk)

上一篇文章《实训二&#xff08;cocos2dx 2.x 打包apk&#xff09;》简单的讲述的利用cocos2dx 2.x引擎在windows平台上打包apk的方法与过程&#xff0c;本文将介绍3.x版本引擎&#xff0c;如何打包apk的问题。 首先&#xff0c;Cygwin在3.x版本引擎上已经用不到了&#xff0c;…