Android Proguard安全加固教你如何让自己的应用程序或SDK更难被反编译--library打包成jar并且混淆

原文地址:https://blog.csdn.net/jspping/article/details/66968367


在android 应用层开发的时候咱们技术人员都或多或少都会接触一些SDK比如so、jar等,这些都是数据类公司提供给互联网开发公司的关于技术核心类

方便的东西,因为是核心所以加密加固是必不可少的工作,本博今天就向大家介绍jar的封装打包以及混淆,完成自己的SDK!在此之前需要给大家说

说so,so是由C/C++语言编译而来,其反编译难度更大,因为反编译之后就是汇编语言,需要懂汇编才能看懂,更重要的是即使懂汇编把其复原也是相

当大的工程,尤其是一些大公司的SDK,那就更别说了,而jar呢反编译的难度就相比so要小很多,所以这也是很多包名和key的验证都放在so的原因!

jar加密加固无外乎就是混淆了,只要你在这个行业做了一段时间就会知道个大概了,混淆就是把 keep 命令之外的变量名、类名、函数名、

attributes、parameter name等全部混淆成一些小写字母之类的,这样这个SDK看起来就会异常的紊乱,但是先前提到过,只要在这个行业做过一段时

间,即使混淆了部分,但大部分的语法还是可以寻到其根源的,所以比较好的方式就是推荐so+jar


①通过library打包自己的SDK

这是笔者自己写的一个SDK,里面主要是用来管理wifi、ap、服务端的文件快传、摄像监控的rtsp推流框架、asyntask管理、网络编程、相机管理,硬加速、局域网组播、二维码

生成和解析等,是用于一个大项目的核心代码,主要是用来降低架构与UI的耦合性,其次就是为了安全,废话不多说先开始介绍library的封装,打包成jar 的SDK最后介绍jar SDK

的混淆加固

首先看看library的构成,如下图:




AndroidManifest.xml 清单文件的配置,如下代码:

[java]  view plain  copy
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     package="jsp.rtsp.server.camera" >  
  3.   
  4.     <application  
  5.         android:allowBackup="true"  
  6.         android:label="@string/app_name"  
  7.         android:supportsRtl="true" >  
  8.     </application>  
  9.   
  10. </manifest>  


我们可以理解为这是一个新建的android application project,因为这本身就是一个ndroid application project,只是特殊的而已,新建一个ndroid application project

然后修改AndroidManifest.xml清单文件去掉不必要的xml节点,完成这一步之后,进行如下图步骤:



接下来弹出如下提示框,进行如下步骤:




这样一个library的建立就完成了!

下面介绍library的编译与依赖的编译

编译的话直接clean就可以编译library,简单粗暴,接着说依赖编译,还是上图描述比较深刻

还是单机选择一个非library的android项目,如下




选择properties项后,弹出如下提示框:




点击OK确认后,进行如下步骤:




执行完该步骤之后,项目会生成一个新的东西,如下图:




下面继续说上面的依赖编译,在完成上面的步骤之后,可以开始依赖编译,就是对library项目进行clean,但再此之前需要执行一下步骤,方便清除上一次的library

缓存,如下图步骤操作,在对library进行clean:




这就是依赖编译,这么做的好处就是可以不用每次更新编译生成新library的时候将jar copy到项目中,非常方便!

好了,关于library的jar SDK封装就完成了,下面开始讲library SDK的混淆与加密加固了!

②通过Proguard 混淆 library打包的jar SDK

Proguard 的使用,Proguard在你的android SDK 路径下的 tools目录下,比如笔者的如下图:




双击打开,下面介绍 Proguard 使用




点击next之后,可以新增自己需要被混淆的jar以及混淆后的jar输出路径,如下图:




备注:其中的android.jar依赖需要根据自己的SDK版本对应,比如你选择的是6.0,那对应选择SDK目录下的platforms的android-23下的android.jar

然后选择next进行下一步




继续 next 执行下一步




下面介绍怎么样配置混淆,以及混淆的具体操作:

1.关于类的混淆:




添加不想被混淆的类:




添加不想被混淆的方法:




添加不想被混淆的变量:




关于内部类和内部接口的混淆,其中内部enum也类似



关于函数和变量方面,笔者怕大家理解不清楚,就随便演示一下,如下图:

1.不混淆方法演示图:

首先看实际代码:

[java]  view plain  copy
  1. /** 
  2.  * @author Engineer-Jsp 
  3.  * @param android.content.Context context 
  4.  * @param jsp.rtsp.server.ap.WiFiApManager.ResponseCallBack call 
  5.  * @return jsp.rtsp.server.ap.WiFiApManager 
  6.  */  
  7. public static WiFiApManager getInstance(Context context, ResponseCallBack call) {  
  8.     if (mWiFiApManager == ) {  
  9.         mWiFiApManager = new WiFiApManager(context, call);  
  10.     }  
  11.     return mWiFiApManager;  
  12. }  

再看混淆的配置:



argument type 看不清吗?没关系,我把它贴出来:

android.content.Context,jsp.rtsp.server.ap.WiFiApManager$ResponseCallBack

你们肯定在想,为什么是WiFiApManager$ResponseCallBack而不是WiFiApManager.ResponseCallBack,这个等下会细说给大家,下面继续演示变量的混淆配置

2. 不混淆变量演示:

首先看一个内部类代码:

[java]  view plain  copy
  1. public class CameraManager {  
  2.   
  3.     private static CameraManager mCameraManager = ;  
  4.     private MediaStream mMediaStream;  
  5.   
  6.     public static interface CameraCallBack {  
  7.         void onSuccess(int code, String msg);  
  8.   
  9.         void onCameraStop();  
  10.   
  11.         void onError(int errcode, String errmsg);  
  12.     }  
  13.   
  14.     /** 
  15.      *  
  16.      * @author Engineer-Jsp 
  17.      * 内部类的演示 
  18.      * 
  19.      */  
  20.     public static class CameraParameters {  
  21.         public int width;  
  22.         public int height;  
  23.     }  


配置不混淆的变量:




好了,到此关于混淆的具体配置都已经讲得差不多了,下面还要给大家说说关于内部类、内部接口等的调用为什么有时候用"$"有时用".",其实这是跟具体配置和

代码的写法有关的,还记得在配置混淆的时候的那具体的提示框吗?没错这就是引起调用的关键



假如上图红色框的2个复选框被勾选了,那么混淆配置以及混淆之后的内部调用是不用带"$"符号的,采用"."符号,比如:WiFiApManager.ResponseCallBack

假如上图红色框的2个复选框没有被勾选,那么混淆配置以及混淆之后的内部调用是带"$"符号的,比如:WiFiApManager$ResponseCallBack,在import 导包的时候也是用"$"而不能用点符号,即使是 new 创建新实例对象的时候,如果他是内部类,就必须要带$符号,如下导包和创建新的实例:

import jsp.rtsp.server.ap.WiFiApManager$ResponseCallBack;

CameraManager$CameraParameters cameraParameters = CameraManager.getSupportResolution(this);

所以在不勾选的情况下,建议大家刻意的去使用内部类和内部接口,除非它们不需要暴露给开发者调用,否则最好不要这样写!这样不规范!

在配置完混淆的具体配置以后,继续next,后面的大概都不用去修改了,一直到 process 选项,选择 process 按钮,就会开始混淆jar

在该 process 界面下,有以下按钮需要注意,如下图:



混淆后使用jd-gui看效果:





编译通过后导入项目与依赖该SDK的项目一起编译




安装效果图:



其中本项目又涉及了很多so库,所以在jni方面最好是不要混淆native的方法,而且C/C++调用java层的方法最好也不要混淆!

关于本篇文章的介绍就这么多,谢谢观博!

附上pro文件:

[java]  view plain  copy
  1. -injars 'D:\Android\Android-6.0-23.06-Build\workspace\jsp.jar'  
  2. -outjars 'D:\Android\Android-6.0-23.06-Build\workspace\jsp-rtsp-server.jar'  
  3.   
  4. -libraryjars 'D:\Java\jre7\lib\rt.jar'  
  5. -libraryjars 'D:\Android\Android-6.0-23.06-Build\workspace\jsp-rtsp-server\libs\zxing.jar'  
  6. -libraryjars 'D:\Android\Android-6.0-23.06-Build\android-6.0-sdk\platforms\android-23\android.jar'  
  7.   
  8. -dontshrink  
  9. -keeppackagenames  
  10.   
  11.   
  12. -keep,allowshrinking class jsp.rtsp.server.ap.WiFiApManager {  
  13.     *** closeWifiAp(...);  
  14.     public static jsp.rtsp.server.ap.WiFiApManager getInstance(android.content.Context,jsp.rtsp.server.ap.WiFiApManager$ResponseCallBack);  
  15.     *** getWiFiApAddress(...);  
  16.     *** openWifiAp(...);  
  17.     *** onDestroy(...);  
  18. }  
  19.   
  20. -keep,allowshrinking interface  jsp.rtsp.server.ap.WiFiApManager$ResponseCallBack {  
  21.     void onWiFiApQrcodeBitmapCall(android.graphics.Bitmap);  
  22. }  
  23.   
  24. -keep,allowshrinking class jsp.rtsp.server.camera.CameraManager {  
  25.     public static jsp.rtsp.server.camera.CameraManager getInstance(android.content.Context,android.view.SurfaceView,jsp.rtsp.server.camera.CameraManager$CameraCallBack);  
  26.     *** updateResolution(...);  
  27.     *** setDgree(...);  
  28.     *** startStream(...);  
  29.     *** getRtspAddress(...);  
  30.     *** stopStream(...);  
  31.     android.hardware.Camera getCamera(...);  
  32.     *** setRtspAddress(...);  
  33.     *** createCamera(...);  
  34.     *** startPreview(...);  
  35.     *** stopPreview(...);  
  36.     *** destroyCamera(...);  
  37.     *** switchCamera(...);  
  38.     *** reStartStream(...);  
  39.     public static void setSupportResolution(android.content.Context);  
  40.     public static jsp.rtsp.server.camera.CameraManager$CameraParameters getSupportResolution(android.content.Context);  
  41. }  
  42.   
  43. -keep,allowshrinking interface  jsp.rtsp.server.camera.CameraManager$CameraCallBack {  
  44.     void onSuccess(int,java.lang.String);  
  45.     void onCameraStop(...);  
  46.     void onError(int,java.lang.String);  
  47. }  
  48.   
  49. -keep,allowshrinking public class jsp.rtsp.server.camera.CameraManager$CameraParameters {  
  50.     public int width;  
  51.     public int height;  
  52. }  
  53.   
  54. -keep,allowshrinking class org.easydarwin.easyipcamera.camera.EasyIPCamera {  
  55.     public static void onIPCameraCallBack(int,int,byte[],int);  
  56. }  
  57.   
  58. # Keep - Applications. Keep all application classes, along with their 'main'  
  59. # methods.  
  60. -keepclasseswithmembers public class * {  
  61.     public static void main(java.lang.String[]);  
  62. }  
  63.   
  64. # Also keep - Enumerations. Keep the special static methods that are required in  
  65. # enumeration classes.  
  66. -keepclassmembers enum  * {  
  67.     public static **[] values();  
  68.     public static ** valueOf(java.lang.String);  
  69. }  
  70.   
  71. # Also keep - Database drivers. Keep all implementations of java.sql.Driver.  
  72. -keep class * extends java.sql.Driver  
  73.   
  74. # Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI,  
  75. # along with the special 'createUI' method.  
  76. -keep class * extends javax.swing.plaf.ComponentUI {  
  77.     public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);  
  78. }  
  79.   
  80. # Keep names - Native method names. Keep all native class/method names.  
  81. -keepclasseswithmembers,allowshrinking class * {  
  82.     native <methods>;  
  83. }  
  84.   
  85. # Remove - System method calls. Remove all invocations of System  
  86. # methods without side effects whose return values are not used.  
  87. -assumenosideeffects public class java.lang.System {  
  88.     public static long currentTimeMillis();  
  89.     static java.lang.Class getCallerClass();  
  90.     public static int identityHashCode(java.lang.Object);  
  91.     public static java.lang.SecurityManager getSecurityManager();  
  92.     public static java.util.Properties getProperties();  
  93.     public static java.lang.String getProperty(java.lang.String);  
  94.     public static java.lang.String getenv(java.lang.String);  
  95.     public static java.lang.String mapLibraryName(java.lang.String);  
  96.     public static java.lang.String getProperty(java.lang.String,java.lang.String);  
  97. }  
  98.   
  99. # Remove - Math method calls. Remove all invocations of Math  
  100. # methods without side effects whose return values are not used.  
  101. -assumenosideeffects public class java.lang.Math {  
  102.     public static double sin(double);  
  103.     public static double cos(double);  
  104.     public static double tan(double);  
  105.     public static double asin(double);  
  106.     public static double acos(double);  
  107.     public static double atan(double);  
  108.     public static double toRadians(double);  
  109.     public static double toDegrees(double);  
  110.     public static double exp(double);  
  111.     public static double log(double);  
  112.     public static double log10(double);  
  113.     public static double sqrt(double);  
  114.     public static double cbrt(double);  
  115.     public static double IEEEremainder(double,double);  
  116.     public static double ceil(double);  
  117.     public static double floor(double);  
  118.     public static double rint(double);  
  119.     public static double atan2(double,double);  
  120.     public static double pow(double,double);  
  121.     public static int round(float);  
  122.     public static long round(double);  
  123.     public static double random();  
  124.     public static int abs(int);  
  125.     public static long abs(long);  
  126.     public static float abs(float);  
  127.     public static double abs(double);  
  128.     public static int max(int,int);  
  129.     public static long max(long,long);  
  130.     public static float max(float,float);  
  131.     public static double max(double,double);  
  132.     public static int min(int,int);  
  133.     public static long min(long,long);  
  134.     public static float min(float,float);  
  135.     public static double min(double,double);  
  136.     public static double ulp(double);  
  137.     public static float ulp(float);  
  138.     public static double signum(double);  
  139.     public static float signum(float);  
  140.     public static double sinh(double);  
  141.     public static double cosh(double);  
  142.     public static double tanh(double);  
  143.     public static double hypot(double,double);  
  144.     public static double expm1(double);  
  145.     public static double log1p(double);  
  146. }  
  147.   
  148. # Remove - Number method calls. Remove all invocations of Number  
  149. # methods without side effects whose return values are not used.  
  150. -assumenosideeffects public class java.lang.* extends java.lang.Number {  
  151.     public static java.lang.String toString(byte);  
  152.     public static java.lang.Byte valueOf(byte);  
  153.     public static byte parseByte(java.lang.String);  
  154.     public static byte parseByte(java.lang.String,int);  
  155.     public static java.lang.Byte valueOf(java.lang.String,int);  
  156.     public static java.lang.Byte valueOf(java.lang.String);  
  157.     public static java.lang.Byte decode(java.lang.String);  
  158.     public int compareTo(java.lang.Byte);  
  159.     public static java.lang.String toString(short);  
  160.     public static short parseShort(java.lang.String);  
  161.     public static short parseShort(java.lang.String,int);  
  162.     public static java.lang.Short valueOf(java.lang.String,int);  
  163.     public static java.lang.Short valueOf(java.lang.String);  
  164.     public static java.lang.Short valueOf(short);  
  165.     public static java.lang.Short decode(java.lang.String);  
  166.     public static short reverseBytes(short);  
  167.     public int compareTo(java.lang.Short);  
  168.     public static java.lang.String toString(int,int);  
  169.     public static java.lang.String toHexString(int);  
  170.     public static java.lang.String toOctalString(int);  
  171.     public static java.lang.String toBinaryString(int);  
  172.     public static java.lang.String toString(int);  
  173.     public static int parseInt(java.lang.String,int);  
  174.     public static int parseInt(java.lang.String);  
  175.     public static java.lang.Integer valueOf(java.lang.String,int);  
  176.     public static java.lang.Integer valueOf(java.lang.String);  
  177.     public static java.lang.Integer valueOf(int);  
  178.     public static java.lang.Integer getInteger(java.lang.String);  
  179.     public static java.lang.Integer getInteger(java.lang.String,int);  
  180.     public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer);  
  181.     public static java.lang.Integer decode(java.lang.String);  
  182.     public static int highestOneBit(int);  
  183.     public static int lowestOneBit(int);  
  184.     public static int numberOfLeadingZeros(int);  
  185.     public static int numberOfTrailingZeros(int);  
  186.     public static int bitCount(int);  
  187.     public static int rotateLeft(int,int);  
  188.     public static int rotateRight(int,int);  
  189.     public static int reverse(int);  
  190.     public static int signum(int);  
  191.     public static int reverseBytes(int);  
  192.     public int compareTo(java.lang.Integer);  
  193.     public static java.lang.String toString(long,int);  
  194.     public static java.lang.String toHexString(long);  
  195.     public static java.lang.String toOctalString(long);  
  196.     public static java.lang.String toBinaryString(long);  
  197.     public static java.lang.String toString(long);  
  198.     public static long parseLong(java.lang.String,int);  
  199.     public static long parseLong(java.lang.String);  
  200.     public static java.lang.Long valueOf(java.lang.String,int);  
  201.     public static java.lang.Long valueOf(java.lang.String);  
  202.     public static java.lang.Long valueOf(long);  
  203.     public static java.lang.Long decode(java.lang.String);  
  204.     public static java.lang.Long getLong(java.lang.String);  
  205.     public static java.lang.Long getLong(java.lang.String,long);  
  206.     public static java.lang.Long getLong(java.lang.String,java.lang.Long);  
  207.     public static long highestOneBit(long);  
  208.     public static long lowestOneBit(long);  
  209.     public static int numberOfLeadingZeros(long);  
  210.     public static int numberOfTrailingZeros(long);  
  211.     public static int bitCount(long);  
  212.     public static long rotateLeft(long,int);  
  213.     public static long rotateRight(long,int);  
  214.     public static long reverse(long);  
  215.     public static int signum(long);  
  216.     public static long reverseBytes(long);  
  217.     public int compareTo(java.lang.Long);  
  218.     public static java.lang.String toString(float);  
  219.     public static java.lang.String toHexString(float);  
  220.     public static java.lang.Float valueOf(java.lang.String);  
  221.     public static java.lang.Float valueOf(float);  
  222.     public static float parseFloat(java.lang.String);  
  223.     public static boolean isNaN(float);  
  224.     public static boolean isInfinite(float);  
  225.     public static int floatToIntBits(float);  
  226.     public static int floatToRawIntBits(float);  
  227.     public static float intBitsToFloat(int);  
  228.     public static int compare(float,float);  
  229.     public boolean isNaN();  
  230.     public boolean isInfinite();  
  231.     public int compareTo(java.lang.Float);  
  232.     public static java.lang.String toString(double);  
  233.     public static java.lang.String toHexString(double);  
  234.     public static java.lang.Double valueOf(java.lang.String);  
  235.     public static java.lang.Double valueOf(double);  
  236.     public static double parseDouble(java.lang.String);  
  237.     public static boolean isNaN(double);  
  238.     public static boolean isInfinite(double);  
  239.     public static long doubleToLongBits(double);  
  240.     public static long doubleToRawLongBits(double);  
  241.     public static double longBitsToDouble(long);  
  242.     public static int compare(double,double);  
  243.     public boolean isNaN();  
  244.     public boolean isInfinite();  
  245.     public int compareTo(java.lang.Double);  
  246.     public <init>(byte);  
  247.     public <init>(short);  
  248.     public <init>(int);  
  249.     public <init>(long);  
  250.     public <init>(float);  
  251.     public <init>(double);  
  252.     public <init>(java.lang.String);  
  253.     public byte byteValue();  
  254.     public short shortValue();  
  255.     public int intValue();  
  256.     public long longValue();  
  257.     public float floatValue();  
  258.     public double doubleValue();  
  259.     public int compareTo(java.lang.Object);  
  260.     public boolean equals(java.lang.Object);  
  261.     public int hashCode();  
  262.     public java.lang.String toString();  
  263. }  
  264.   
  265. # Remove - String method calls. Remove all invocations of String  
  266. # methods without side effects whose return values are not used.  
  267. -assumenosideeffects public class java.lang.String {  
  268.     public <init>();  
  269.     public <init>(byte[]);  
  270.     public <init>(byte[],int);  
  271.     public <init>(byte[],int,int);  
  272.     public <init>(byte[],int,int,int);  
  273.     public <init>(byte[],int,int,java.lang.String);  
  274.     public <init>(byte[],java.lang.String);  
  275.     public <init>(char[]);  
  276.     public <init>(char[],int,int);  
  277.     public <init>(java.lang.String);  
  278.     public <init>(java.lang.StringBuffer);  
  279.     public static java.lang.String copyValueOf(char[]);  
  280.     public static java.lang.String copyValueOf(char[],int,int);  
  281.     public static java.lang.String valueOf(boolean);  
  282.     public static java.lang.String valueOf(char);  
  283.     public static java.lang.String valueOf(char[]);  
  284.     public static java.lang.String valueOf(char[],int,int);  
  285.     public static java.lang.String valueOf(double);  
  286.     public static java.lang.String valueOf(float);  
  287.     public static java.lang.String valueOf(int);  
  288.     public static java.lang.String valueOf(java.lang.Object);  
  289.     public static java.lang.String valueOf(long);  
  290.     public boolean contentEquals(java.lang.StringBuffer);  
  291.     public boolean endsWith(java.lang.String);  
  292.     public boolean equalsIgnoreCase(java.lang.String);  
  293.     public boolean equals(java.lang.Object);  
  294.     public boolean matches(java.lang.String);  
  295.     public boolean regionMatches(boolean,int,java.lang.String,int,int);  
  296.     public boolean regionMatches(int,java.lang.String,int,int);  
  297.     public boolean startsWith(java.lang.String);  
  298.     public boolean startsWith(java.lang.String,int);  
  299.     public byte[] getBytes();  
  300.     public byte[] getBytes(java.lang.String);  
  301.     public char charAt(int);  
  302.     public char[] toCharArray();  
  303.     public int compareToIgnoreCase(java.lang.String);  
  304.     public int compareTo(java.lang.Object);  
  305.     public int compareTo(java.lang.String);  
  306.     public int hashCode();  
  307.     public int indexOf(int);  
  308.     public int indexOf(int,int);  
  309.     public int indexOf(java.lang.String);  
  310.     public int indexOf(java.lang.String,int);  
  311.     public int lastIndexOf(int);  
  312.     public int lastIndexOf(int,int);  
  313.     public int lastIndexOf(java.lang.String);  
  314.     public int lastIndexOf(java.lang.String,int);  
  315.     public int length();  
  316.     public java.lang.CharSequence subSequence(int,int);  
  317.     public java.lang.String concat(java.lang.String);  
  318.     public java.lang.String replaceAll(java.lang.String,java.lang.String);  
  319.     public java.lang.String replace(char,char);  
  320.     public java.lang.String replaceFirst(java.lang.String,java.lang.String);  
  321.     public java.lang.String[] split(java.lang.String);  
  322.     public java.lang.String[] split(java.lang.String,int);  
  323.     public java.lang.String substring(int);  
  324.     public java.lang.String substring(int,int);  
  325.     public java.lang.String toLowerCase();  
  326.     public java.lang.String toLowerCase(java.util.Locale);  
  327.     public java.lang.String toString();  
  328.     public java.lang.String toUpperCase();  
  329.     public java.lang.String toUpperCase(java.util.Locale);  
  330.     public java.lang.String trim();  
  331. }  
  332.   
  333. # Remove - StringBuffer method calls. Remove all invocations of StringBuffer  
  334. # methods without side effects whose return values are not used.  
  335. -assumenosideeffects public class java.lang.StringBuffer {  
  336.     public <init>();  
  337.     public <init>(int);  
  338.     public <init>(java.lang.String);  
  339.     public <init>(java.lang.CharSequence);  
  340.     public java.lang.String toString();  
  341.     public char charAt(int);  
  342.     public int capacity();  
  343.     public int codePointAt(int);  
  344.     public int codePointBefore(int);  
  345.     public int indexOf(java.lang.String,int);  
  346.     public int lastIndexOf(java.lang.String);  
  347.     public int lastIndexOf(java.lang.String,int);  
  348.     public int length();  
  349.     public java.lang.String substring(int);  
  350.     public java.lang.String substring(int,int);  
  351. }  
  352.   
  353. # Remove - StringBuilder method calls. Remove all invocations of StringBuilder  
  354. # methods without side effects whose return values are not used.  
  355. -assumenosideeffects public class java.lang.StringBuilder {  
  356.     public <init>();  
  357.     public <init>(int);  
  358.     public <init>(java.lang.String);  
  359.     public <init>(java.lang.CharSequence);  
  360.     public java.lang.String toString();  
  361.     public char charAt(int);  
  362.     public int capacity();  
  363.     public int codePointAt(int);  
  364.     public int codePointBefore(int);  
  365.     public int indexOf(java.lang.String,int);  
  366.     public int lastIndexOf(java.lang.String);  
  367.     public int lastIndexOf(java.lang.String,int);  
  368.     public int length();  
  369.     public java.lang.String substring(int);  
  370.     public java.lang.String substring(int,int);  
  371. }  

猜你喜欢

转载自blog.csdn.net/try_zp_catch/article/details/80194663