apk极致优化

体积缩小,apk打包去掉无用资源,启动优化,后台任务处理,白屏处理,混淆,ViewPager+fragment优化等过程

混淆模板

使用:直接复制到app/proguard-rules.pro文件中即可,处理混淆时根据第三方提供的混淆代码不从到其中,以及实体类保持等

  • 减少apk体积
  • 避免无用的资源编译到apk文件中
  • 安全性
#-------------------------------------------定制化区域----------------------------------------------
#---------------------------------1.实体类---------------------------------

-keep class com.face.factoryageing.entity.** { *; }

#-------------------------------------------------------------------------

#---------------------------------2.第三方包-------------------------------

#eventBus
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

#glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

-keep public class cn.jzvd.JZMediaSystem {*; }
-keep public class cn.jzvd.demo.CustomMedia.CustomMedia {*; }
-keep public class cn.jzvd.demo.CustomMedia.JZMediaIjk {*; }
-keep public class cn.jzvd.demo.CustomMedia.JZMediaSystemAssertFolder {*; }

-keep class tv.danmaku.ijk.media.player.** {*; }
-dontwarn tv.danmaku.ijk.media.player.*
-keep interface tv.danmaku.ijk.media.player.** { *; }
#log4j

#-------------------------------------------------------------------------

#---------------------------------3.与js互相调用的类------------------------

-keepclasseswithmembers class com.demo.login.bean.ui.MainActivity$JSInterface {
      <methods>;
}

#-------------------------------------------------------------------------

#---------------------------------4.反射相关的类和方法-----------------------
# 有
#----------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------

#-------------------------------------------基本不用动区域--------------------------------------------
#---------------------------------基本指令区----------------------------------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-printmapping proguardMapping.txt
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
#----------------------------------------------------------------------------

#---------------------------------默认保留区---------------------------------
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}

-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
-keep class **.R$* {
 *;
}
-keepclassmembers class * {
    void *(**On*Event);
}
#----------------------------------------------------------------------------

#---------------------------------webview------------------------------------
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
   public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, jav.lang.String);
}
#----------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------

# 删除代码中Log相关的代码
#-assumenosideeffects class android.util.Log {
#    public static boolean isLoggable(java.lang.String, int);
#    public static int v(...);
#    public static int i(...);
#    public static int w(...);
#    public static int d(...);
#    public static int e(...);
#}

app/build.gradle处理混淆

android{
 buildTypes {
            release {
                signingConfig signingConfigs.release
                minifyEnabled true
                // Zipalign优化
                zipAlignEnabled true
                // 移除无用的resource文件
                shrinkResources true
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
            debug {
                signingConfig signingConfigs.debug
                minifyEnabled true
                // Zipalign优化
                zipAlignEnabled true
                // 移除无用的resource文件
                shrinkResources true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
}

android系统framework.jar优化

在app/build.gradle文件中修改

  • 参与编译,但是不jar的内容加入到APK中
  • 使用场景(开发系统apk,framework.jar通常都比较大,大致在8M以上)使用以下方式可避免编译到apk中
  • 标签中注释下方代码
dependencies {

    //implementation fileTree(dir: "libs", include: ["*.jar"])
    compileOnly files('libs\\framework.jar')

}

 根目录下的build.gradle

allprojects {
    repositories {
        ...
        gradle.projectsEvaluated {
            tasks.withType(JavaCompile) {
                options.compilerArgs << '-Xbootclasspath/p:app/libs/classes.jar'
            }
        }

    }
}

后台处理耗时任务,初始化操作 

耗时任务与主线程同步进行,InitializeService 负责处理复杂耗时的初始化操作

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        InitializeService.start(this);
    }
    @Override
    protected void attachBaseContext(android.content.Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}
/**
 * Create on 2019/10/16
 * author chtj
 * desc 启动app时的优化
 */
public class InitializeService extends IntentService {
    private static final String TAG="InitializeService";
    private static final String ACTION_INIT_WHEN_APP_CREATE = "com.anly.githubapp.service.action.INIT";

    public InitializeService() {
        super("InitializeService");
    }

    public static void start(Context context) {
        Intent intent = new Intent(context, InitializeService.class);
        intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
                performInit();
            }
        }
    }

    private void performInit() {
        //在这里进行初始化的相关代码
        KLog.init(true);
        KLog.d(TAG,"performInit");
        //CrashHandler.getInstance().init(this);
        //CrashHandler.getInstance().init(getApplication());
        //KLog.d("performInit begin:" + System.currentTimeMillis());
        //需要在 Application 的 onCreate() 中调用一次 BaseIotTools.instance()....
        //1080,1920是为了适配而去设置相关的值
        //设置宽度|高度布局尺寸 layout 布局文件以pt为单位 setBaseScreenParam(1080,1920,true)
        BaseIotUtils.instance().
                setBaseScreenParam(1080,1920,true).
                setCreenType(SCREEN_TYPE.WIDTH).//按照宽度适配
                create(getApplication());

    }

}

Activity启动优化 

Activity只负责界面基础view初始化操作,耗时任务在异步任务中操作,互不干扰,避免UI产生卡顿

/**
 * Create on 2019/10/16
 * author chtj
 * desc $ 启动页
 */
public class StartPageAty extends BaseActivity {
    private static final String TAG="StartPageAty";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //先进入启动页,什么都不做,只是做一个跳转
        startActivity(new Intent(StartPageAty.this, MainActivity.class));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try{
            boolean isFrist= SPUtils.getBoolean("isFirst",true);
            if(isFrist){
                //如果是第一次进来
                SPUtils.putBoolean("isFirst",false);
            }else{
                //如果是第二次及以后进来

            }
        }catch(Exception e){
            e.printStackTrace();
            KLog.e(TAG,"errMeg:"+e.getMessage());
        }
    }
}
public class MainActivity extends BaseActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //启动完毕之后结束开始页
        AppManager.getAppManager().finishActivity(StartPageAty.class);
        //耗时任务放到线程中执行 
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                //这里异步执行耗时任务
                List<File> fileList=getFileList();
            }
        });
    }
}

drawable/logo_splash.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底层白色 -->
    <item android:drawable="@color/white" />

    <!-- 顶层Logo居中 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/app_img" />
    </item>
</layer-list>

 res/values/styles.xml中添加

 <!--
    一:AndroidManifest.xml application中的theme使用该主题
    二:启动成功后再Aty中设置为正常的主题
    三:其他Aty设置为正常的AppTheme
    这样打开桌面图标会马上显示logo,不会出现黑/白屏,
    直到Activity启动完成,替换主题,logo消失,
    -->
    <style name="SplashTheme" parent="AppTheme">
        <item name="android:windowBackground">@drawable/logo_splash</item>
        <item name="android:windowFullscreen">true</item>
    </style>

内存申请及启动页配置

activity_main布局文件推荐使用RelativeLayout,可对耗时有一部分优化,尽量减少布局层次,嵌套等复杂布局。

AndroidManifest.xml中 android:largeHeap="true"分配更多内存提供给apk使用

<manifest>
     <application
        android:largeHeap="true"
        android:persistent="true">
         <!--启动页-->
        <activity
            android:name=".startpage.StartPageAty"
            android:theme="@style/SplashTheme">
           <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--首页-->
        <activity android:name=".startpage.MainActivity"/>
        <!--在服务里面进行一些application应该执行的初始化操作-->
        <service android:name=".myapplication.InitializeService" />
        
    </application>
</manfiest>

Fragment+ViewPager优化

将项目中的Fragment继承LazyLoadFragment实现懒加载

/**
 * Create on 2020/8/13
 * author chtj
 * desc
 */
public abstract class LazyLoadFragment extends Fragment {
    /**
     * 视图是否已经初初始化
     */
    protected boolean isInit = false;
    protected boolean isLoad = false;
    protected final String TAG = "LazyLoadFragment";
    private View view;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(setContentView(), container, false);
        isInit = true;
        /**初始化的时候去加载数据**/
        isCanLoadData();
        return view;
    }

    /**
     * 视图是否已经对用户可见,系统的方法
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isCanLoadData();
    }

    /**
     * 是否可以加载数据
     * 可以加载数据的条件:
     * 1.视图已经初始化
     * 2.视图对用户可见
     */
    private void isCanLoadData() {
        if (!isInit) {
            return;
        }

        if (getUserVisibleHint()) {
            lazyLoad();
            isLoad = true;
        } else {
            if (isLoad) {
                stopLoad();
            }
        }
    }

    /**
     * 视图销毁的时候讲Fragment是否初始化的状态变为false
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isInit = false;
        isLoad = false;

    }


    /**
     * 设置Fragment要显示的布局
     *
     * @return 布局的layoutId
     */
    protected abstract int setContentView();

    /**
     * 获取设置的布局
     *
     * @return
     */
    protected View getContentView() {
        return view;
    }

    /**
     * 找出对应的控件
     *
     * @param id
     * @param <T>
     * @return
     */
    protected <T extends View> T findViewById(int id) {

        return (T) getContentView().findViewById(id);
    }

    /**
     * 当视图初始化并且对用户可见的时候去真正的加载数据
     */
    protected abstract void lazyLoad();

    /**
     * 当视图已经对用户不可见并且加载过数据,如果需要在切换到其他页面时停止加载数据,可以覆写此方法
     */
    protected void stopLoad() {
    }

}

猜你喜欢

转载自blog.csdn.net/qq_35809640/article/details/108420205