Android 资源保护问题——探索

apk文件使用解压工具就能看到drawable等资源,但是有些游戏中的图片资源却是无法看到的。

这个问题探索了许久……

【1】图片资源不放置在drawable文件下,放在assets中(但是解压apk,同样能看到图片资源),以下说说使用方法。

分析:Ⅰ)当图片资源放在drawable中的时候,能有相应的Id去解析: BitmapFactory.decodeResource(res, id)

      如果放置在assets下,就需要根据文件的名字去解析(Android提供AssetManager)。

      Ⅱ)可以自己建立多层目录,方便管理。

      Ⅲ)这样的解析过程,耗费的时间要比根据Id解析要多(手机越来越智能,这点时间基本看不出来)。

代码:

/**
     * 从Assets中读取图片
     * @param fileName :assets根目录下 "a.png",有子文件夹的 "abc/a.png"
     * @return
     */
      public static Bitmap getImageFromAssets(Context context, String fileName)
      {
          Bitmap image = null;
          AssetManager am = context.getResources().getAssets();
          try
          {
              InputStream is = am.open(fileName);
              image = BitmapFactory.decodeStream(is);
              is.close();
          }
          catch (IOException e)
          {
              e.printStackTrace();
          }
          return image;
      }

【2】图片资源打包在jar下,然后导入工程(但是解压apk,同样能看到图片资源)

分析:使用过一下第三方的jar包,在apk解压后是看不到的,尝试看看。最终发现jar包中的assets文件在apk中可见了。

Step1:打包jar

工程->右键->Export->Java/jar file->选择需要打包的src 和 assets(如下图)


Step2:解读assets中的图片,同【1】

Step3:打包apk,然后发现jar包中的assets和当前工程的assets合并了!

 

【3】图片资源加密,然后在assets文件下读取(可以实现资源保护,但是貌似比较耗时)

分析:通过某种方式对图片预先加密,然后在Android程序中解密,在转换成Bitmap。

可能别的应用程序就是这样做的吧,哪位大神有妙招,给介绍一下吧!(下面介绍一下简单方法)

Step1:加密,采用文件流方式,读取资源,然后修改,最后生成文件(随便格式都可以,就不能知道是图片了)

Ⅰ)每隔多少个字节添加一个指定的字节

Ⅱ)每隔多少个字节,交换字节(代码示例)

public class KMD1 {
    public static void encrypt(String filePath){
           byte[] tempbytes = new byte[5000];
           try {
            InputStream in = new FileInputStream(filePath);
            OutputStream out = new FileOutputStream(filePath.subSequence(0, filePath.lastIndexOf("."))+"2.jpg")
            while (in.read(tempbytes) != -1) {//简单的交换
                byte a = tempbytes[0];
                tempbytes[0] = tempbytes[1];
                tempbytes[1] = a;
                out.write(tempbytes);//写文件
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        KMD1.encrypt("D:/a.jpg");
    }
}

Step2:解密,与加密过程反向即可。

      /**
* 从Assets中读取图片
* @param fileName
* @return
*/
 public static Bitmap getImageFromAssets(Context context, String fileName)
 {
     Bitmap image = null;
     AssetManager am = context.getResources().getAssets();
     try
     {
         InputStream is = am.open(fileName);
         byte[] buffer = new byte[1000000];//足够大
         is.read(buffer);
         for(int i=0; i<buffer.length; i+= 5000){//与加密相同
          byte temp = buffer[i];
          buffer[i] = buffer[i+1];
          buffer[i+1] = temp;
         }
         image = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
         is.close();
     }
     catch (IOException e)
     {
         e.printStackTrace();
     }
     return image;
 }

【3】使用setPixel()和getPixel()对每个像素点进行加密,然后在使用的时候在还原

分析:通过Bitmap.getPixel(x, y)得到color值,对color的rgb值加密操作,然后setPixel(x,y,color)

Step1:懒得写了,直接贴代码:

注意:bitmap一定要copy一份,然后第二个值为true才能对其setPixel,不然会报错的;代码中的encrypt和decrypt就是你加密解密过程;

严重问题:对bitmap setPixel然后在getPixel,color值竟然不是set的值,有偏差,不知道为什么。有能解决这个问题的,请留言一下。

Bitmap temp_bitmap = image.copy(Bitmap.Config.ARGB_8888, true);  

            int width = temp_bitmap.getWidth();
            int height = temp_bitmap.getHeight();
            int[] pixels = new int[width * height];
            //temp_bitmap.getPixels(pixels, 0, width, 0, 0, width, height);  

            for(int i = 0; i < height; i++)
            {
                for(int j = 0; j < width; j++)
                {
                    int color = temp_bitmap.getPixel(i, j);
                    int r = Color.red(color);
                    int g = Color.green(color);
                    int b = Color.blue(color);
                    int alpha = Color.alpha(color);
                    //if(alpha != 0)
                    {
                        r = encrptyRGB(r, 2*(i*j));
                        g = encrptyRGB(g, 4*(i*j));
                        b = encrptyRGB(b, 6*(i*j));  

                        color = Color.argb(alpha, r, g, b);
                        pixels[width * i + j] = color;
                        //temp_bitmap.setPixel(i, j, color);
                    }  

                }
            }
            temp_bitmap.setPixels(pixels, 0, width, 0, 0, width, height);  

            for(int i = 0; i < height; i++)
            {
                for(int j = 0; j < width; j++)
                {
                    int color = temp_bitmap.getPixel(i, j);
                    int r = Color.red(color);
                    int g = Color.green(color);
                    int b = Color.blue(color);
                    int alpha = Color.alpha(color);
                    //if(alpha != 0)
                    {
                        r = decryptRGB(r, 2*(i*j));
                        g = decryptRGB(g, 4*(i*j));
                        b = decryptRGB(b, 6*(i*j));  

                        color = Color.argb(alpha, r, g, b);
                        pixels[width * i + j] = color;
                        //temp_bitmap.setPixel(i, j, color);
                    }  

                }
            }
            temp_bitmap.setPixels(pixels, 0, width, 0, 0, width, height);  

            return temp_bitmap;  

【?】继续探索中,忘大神指教!感激不尽!

时间: 2024-10-18 15:13:14

Android 资源保护问题——探索的相关文章

Android开发艺术探索——第七章:Android动画深入分析

Android开发艺术探索--第七章:Android动画深入分析 Android的动画可以分成三种,view动画,帧动画,还有属性动画,其实帧动画也是属于view动画的一种,,只不过他和传统的平移之类的动画不太一样的是表现形式上有点不一样,view动画是通过对场景的不断图像交换而产生的动画效果,而帧动画就是播放一大段图片,很显然,图片多了会OOM,属性动画通过动态的改变对象的属性达到动画效果,也是api11的新特性,在低版本无法使用属性动画,但是我们依旧有一些兼容库,OK,我们还是继续来看下详细

Android自定义View探索(一)—生命周期

Activity代码: public class FiveActivity extends AppCompatActivity { private MyView myView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e("log", "Activity生命周期:onCreate"); setConte

Android艺术开发探索第三章————View的事件体系(下)

Android艺术开发探索第三章----View的事件体系(下) 在这里就能学习到很多,主要还是对View的事件分发做一个体系的了解 一.View的事件分发 上篇大致的说了一下View的基础知识和滑动,现在我们再来聊聊一个比较核心的知识点,那就是事件分发了,而且他还是一个难点,我们更加应该掌握,View的滑动冲突一直都是很苦恼的,这里,我们就来一起探索一下 1.点击事件的传递规则 我们分析的点击事件可不是View.OnClickListener,而是我们MotionEvent,即点击事件,关于M

Android开发艺术探索——第二章:IPC机制(上)

Android开发艺术探索--第二章:IPC机制(上) 本章主要讲解Android的IPC机制,首先介绍Android中的多进程概念以及多进程开发模式中常见的注意事项,接着介绍Android中的序列化机制和Binder,然后详细的介绍Bundle,文件共享,AIDL,Messenger,ContentProvider和Socker等进程间通讯的方法,为了更好的使用AIDL进行进程间通讯,本章引入了Binder连接池的概念,最后,本章讲解各种进程间通信方式的优缺点和使用场景,通过本章,可以让读者对

Android艺术开发探索——第二章:IPC机制(下)

Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvider ContentProvider是Android中提供的专门用来不同应用之间数据共享的方式,从这一点来看,他天生就是适合进程间通信,和Messenger一样,ContentProvider的底层实现同样也是Binder,由此可见,Binder在Android系统中是何等的重要,虽然Conten

【读书笔记】【Android 开发艺术探索】第4章 View 的工作原理

一.基础知识 1.ViewRoot 和 DecorView ViewRoot 对应 ViewRootImpl 类,它是连接 WindowManager 和 DecorView 的纽带,View 的三大流程都是通过 ViewRoot 来完成的.在ActivityThread 中,当 Activity 对象被创建完毕后,会将 DecorView 添加到 Window 中,同时会创建 ViewRoot 对象. DecorView 添加到窗口 Window 的过程. 图片来自https://yq.ali

Android开发艺术探索读书笔记——进程间通信

1. 多进程使用场景 1) 应用某些模块因为特殊需求需要运行在单独进程中.如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会因为应用程序进程crash而受影响. 2) 为加大一个应用可使用的内存,需要多进程来获取多份内存空间. 2. 如何开启多进程 给四大组件(Activity.Service.Receiver.ContentProvider)在AndroidMainfest中指定android:process属性指定. 如果进程以":"开头的进程,代表应用的私有进程,其

Android开发艺术探索——第一章:Activity的生命周期和启动模式

Android开发艺术探索--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activity搬上来了,也确实,和Activity打交道的次数基本上是最多的,而且他的内容和知识点也是很多的,非常值得我们优先把他掌握,Activity中文翻译过来就是"活动"的意思,但是主席觉得这样翻译有些生硬,直接翻译成"界面"可能更好,的确,Activity主要也是用于UI效

Android插件化探索(三)免安装运行Activity(上)

[Android插件化探索(一)类加载器DexClassLoader] [Android插件化探索(二)资源加载] 前情提要 在上一篇中有一个细节没有提到,那就是getResourcesForApplication和AssetManager的区别. getResourcesForApplication getResourcesForApplication(String packageName),很显然需要传入一个包名,换言之,这个插件必须已经被安装在系统内,然后才能通过包名来获取资源.你可能会想