Android中Release版本去掉Log的方法

一、自定义BuildConfig字段

在gradle配置文件中,定义LOG字段,默认为true

buildConfigField "boolean", "LOG", "true"

同步一下工程,查看app/build/generated/source/BuildConfig/Build Varients/package name/BuildConfig 文件。

可以看到自动添加了一个LOG字段

  // Fields from default config.
  public static final boolean LOG = true;

这样我们就可以在工程中Log中使用这个开关了

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    public static final boolean DEBUG = BuildConfig.LOG;

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

        if (DEBUG) {
            Log.d(TAG, "hello world!");
        }
    }
}

具体配置如下:

android {
    compileSdkVersion 24
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "test.hpp.cn.testcase"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"

        buildConfigField("boolean", "LOG", "true")
    }
    buildTypes {
        release {
            minifyEnabled false
            buildConfigField("boolean", "LOG", "false")
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

上面我们可以看到,默认配置defaultConfig中LOG字段设置为true,在release版本中,Log自动设置为false。并且我们也可以根据自己的需要进行配置。

二、使用Proguard配置文件

默认的Proguard配置文件在$ANDROID_HOME\sdk\tools\proguard 目录下。
1. proguard-android.txt 默认的Proguard配置文件(未优化)
2. proguard-android-optimize.txt 默认的Proguard配置文件(已优化)
3. proguard-project.txt 默认的用户定制Proguard配置文件。

在gradle中配置如下:

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

另外,在proguard-rules.pro文件中,添加我们的优化项,也就是去掉Log。

-assumenosideeffects class android.util.Log{
    public static *** v(...);
    public static *** i(...);
    public static *** d(...);
    public static *** w(...);
    public static *** e(...);
}

这样在打包release包的时候就可以移除所有的Log,我们也不需要加开关了。

参考文章:
GRADLE自定义你的BUILDCONFIG

Android项目中Proguard配置文件的定制

AndroidStudio下ProGuard混淆打包

欢迎关注微信公众号:DroidMind
精品内容独家发布平台


呈现与博客不一样的技术干货

<think>我们正在讨论Android中通过MediaProjection获取buffer数据的方法。根据引用[2],我们知道MediaProjection可以捕获屏幕画面,并且可以使用ImageReader来获取Surface,从而读取画面数据。关键步骤:1.创建ImageReader对象,指定所需的宽度、高度和图像格式(例如,PixelFormat.RGBA_8888)。2.从ImageReader获取Surface,并将这个Surface设置给VirtualDisplay。3.当有新的一帧图像可用时,通过ImageReader的`acquireLatestImage()`或`acquireNextImage()`方法获取Image对象。4.从Image对象中获取ByteBuffer,这样就可以访问图像的原始数据。注意:在创建VirtualDisplay时,要使用正确的屏幕尺寸(使用getRealMetrics获取,以避免导航条被截断)。下面是一个具体的示例代码:```java//假设我们已经获得了MediaProjection对象(mediaProjection)和屏幕尺寸(width,height)//创建ImageReaderImageReaderimageReader=ImageReader.newInstance(width,height,PixelFormat.RGBA_8888,2);//最后一个参数是最大图像数//获取ImageReader的SurfaceSurfacesurface=imageReader.getSurface();//创建VirtualDisplayVirtualDisplayvirtualDisplay=mediaProjection.createVirtualDisplay("ScreenCapture",//显示名称width,height,//宽高getResources().getDisplayMetrics().densityDpi,//密度DPIDisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,//标志surface,//输出Surfacenull,//回调null//处理程序);//设置ImageReader的监听器,当有新图像可用时触发imageReader.setOnImageAvailableListener(newImageReader.OnImageAvailableListener(){@OverridepublicvoidonImageAvailable(ImageReaderreader){Imageimage=null;try{image=reader.acquireLatestImage();if(image!=null){Image.Plane[]planes=image.getPlanes();if(planes.length>0){//通常RGBA_8888格式只有一个planeByteBufferbuffer=planes[0].getBuffer();//现在buffer中就是图像的原始数据//注意:buffer中的数据可能是按行存储的,并且可能有行填充(stride)intpixelStride=planes[0].getPixelStride();introwStride=planes[0].getRowStride();introwPadding=rowStride-pixelStride*width;//处理buffer数据...}}}catch(Exceptione){e.printStackTrace();}finally{if(image!=null){image.close();}}}},null);//可以指定Handler,null表示使用当前线程的Looper```注意:-使用完Image后必须关闭,否则会导致后续无法获取图像。-图像格式为RGBA_8888时,每个像素4个字节。但是要注意,由于内存对齐的原因,每行的实际字节数(rowStride)可能大于width*4,因此需要处理行填充。-如果需要将图像保存为文件或传输,可能需要去除填充或进行其他处理。另外,根据引用[2],如果要做录屏直播等,还可以结合OpenGLES进行处理,将图像数据编码为视频流。但这里我们只关注如何获取buffer数据。最后,在不需要的时候,记得释放资源:```javavirtualDisplay.release();imageReader.close();```以上就是通过MediaProjection和ImageReader获取buffer数据的基本方法。</think>在 Android 中通过 MediaProjection 获取 buffer 数据,主要使用 `ImageReader` 配合 `VirtualDisplay` 实现。以下是具体实现方法: ### 核心步骤 1. **创建 ImageReader** ```java // 获取真实屏幕尺寸(含导航条) DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(metrics); // 关键点[^2] int width = metrics.widthPixels; int height = metrics.heightPixels; // 创建ImageReader(RGBA_8888格式可获取原始buffer) ImageReader imageReader = ImageReader.newInstance( width, height, PixelFormat.RGBA_8888, // 支持直接获取ByteBuffer 2 // 最大图像数 ); ``` 2. **设置 VirtualDisplay** ```java // 获取ImageReader的Surface Surface surface = imageReader.getSurface(); // 创建虚拟显示器 VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, metrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, // 关键:输出到ImageReader的Surface[^2] null, null ); ``` 3. **获取图像数据** ```java imageReader.setOnImageAvailableListener(reader -> { try (Image image = reader.acquireLatestImage()) { if (image != null) { // 获取图像Planes(RGBA格式通常只有1个plane) Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); // 处理buffer数据(示例:复制到字节数组) byte[] data = new byte[buffer.remaining()]; buffer.get(data); // 使用数据(如保存文件/网络传输等) processImageData(data, width, height); } } catch (Exception e) { Log.e("Capture", "Error processing image", e); } }, null); ``` ### 关键注意事项 1. **尺寸获取** 必须使用 `getRealMetrics()` 而非 `getMetrics()`,确保系统导航条区域[^2]。 2. **Buffer格式** `PixelFormat.RGBA_8888` 每像素占4字节,内存布局为: ``` stride = 每行字节数(可能含填充) pixel_stride = 4(R|G|B|A 各1字节) ``` 3. **资源释放** ```java // 使用完毕后释放 virtualDisplay.release(); imageReader.close(); mediaProjection.stop(); ``` ### 完整工作流程 ```mermaid graph TD A[获取MediaProjection权限] --> B[创建ImageReader] B --> C[创建VirtualDisplay绑定Surface] C --> D[屏幕画面输出到ImageReader] D --> E[通过OnImageAvailableListener获取Image] E --> F[从Image.Plane提取ByteBuffer] F --> G[处理原始像素数据] ``` ### 性能优化建议 1. **降低分辨率** 若不需要全高清,可缩小 `ImageReader` 尺寸减少内存占用 2. **复用Buffer** 使用 `ByteBuffer.allocateDirect()` 创建可复用缓冲区 3. **格式选择** 如需更高性能,考虑 `PixelFormat.RGB_565`(每像素2字节,无透明通道) > 实际应用中,这种技术广泛用于屏幕录制[^2]、实时投屏、游戏直播等场景。注意Android 10+对后台截屏有额外限制,需在前台服务中实现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值