在这个一搜一大把解决方案的年代,我们有时候可以多去学习下人家的技术和方案,写这篇文章的时候,只是想把好早前就跟着玩了一把多渠道快速打包的方法实现总结下,方便以后万一在什么场景需要用的时候拿出来看看。至于原文,有好多资源,大家可以搜一下,我这里暂时参考了这篇文章点击打开链接。我只是代码搬运工。
首先,新建一个空项目,很简单,编辑activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.jianzou.thread.MainActivity">
<Button
android:id="@+id/btn_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"/>
</RelativeLayout>
很简单,然后再MainActivity中引用下:
public class MainActivity extends AppCompatActivity
{
Button btn_01;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_01 = (Button) findViewById(R.id.btn_01);
btn_01.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent i = new Intent(MainActivity.this,OtherActivity.class);
startActivity(i);
}
});
}
创建OtherActivity:
package com.jianzou.thread;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.widget.Button;
/**
* Created by JianZou on 2016/12/5.
*/
public class OtherActivity extends AppCompatActivity
{
Button btn_01;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_01 = (Button) findViewById(R.id.btn_01);
String channel = MutiChannelConfig.getChannel(this);
btn_01.setText(channel );
}
}
package com.jianzou.thread;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.util.Log;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Created by JianZou on 2016/12/5.
*/
public class MutiChannelConfig
{
public static final String Version = "version";
public static final String Channel = "channel";
public static final String DEFAULT_CHANNEL = "netease";
public static final String Channel_File = "channel";
public static String getChannelFromMeta(Context context)
{
ApplicationInfo appinfo = context.getApplicationInfo();
String sourceDir = appinfo.sourceDir;
String ret = "";
ZipFile zipfile = null;
try
{
zipfile = new ZipFile(sourceDir);
Enumeration<?> entries = zipfile.entries();
while (entries.hasMoreElements())
{
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
if (entryName.startsWith("META-INF") && entryName.contains("channel_"))
{
ret = entryName;
break;
}
}
} catch (IOException e)
{
e.printStackTrace();
} finally
{
if (zipfile != null)
{
try
{
zipfile.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
String[] split = ret.split("_");
if (split != null && split.length >= 2)
{
return ret.substring(split[0].length() + 1);
} else
{
return DEFAULT_CHANNEL;
}
}
/**
* 得到渠道名
*
* @param mContext
* @return
*/
public static String getChannel(Context mContext)
{
String channel = "";
if (isNewVersion(mContext))
{//是新版本
Log.e("isNewVersion %s", "isNewVersion");
saveChannel(mContext);//保存当前版本
channel = getChannelFromMeta(mContext);
} else
{
channel = getCachChannel(mContext);
}
return channel;
}
/**
* 保存当前的版本号和渠道名
*
* @param mContext
*/
public static void saveChannel(Context mContext)
{
SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
SharedPreferences.Editor mSettinsEd = mSettinsSP.edit();
mSettinsEd.putString(Version, APPUtils.getAppVersion(mContext));
mSettinsEd.putString(Channel, getChannelFromMeta(mContext));
//提交保存
mSettinsEd.commit();
}
private static boolean isNewVersion(Context mContext)
{
SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
String version = APPUtils.getAppVersion(mContext);
Log.e("version%s", version);
return !mSettinsSP.getString(Version, "").equals(version);
}
private static String getCachChannel(Context mContext)
{
SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
return mSettinsSP.getString(Channel, DEFAULT_CHANNEL);
}
}
记得在AndroidManifest.xml中注册OtherActivity,好,看到MutiChannelConfig这个类,这个也是打包提供的类,在getChannel(Context mContext)这个方法这里,我之前的猜测是:如果我的包在用此脚本打包后,对应的渠道名就应该会从这个方法返回,如果返回了,我就显示在这个button上,否则,button显示为NETEASE。为了验证这个猜想,开始着手实验看看呗!
APP工程很简单,写完了,自己申请个key,这个不多说了,搞过Android开发的老司机们都很熟的。将上面的项目用自己的key先打包,
下载安装python环境:点击打开链接
下载python脚本:点击打开链接
Python环境的安装,很简单,此处略过,环境安装好后,看下载的Python脚本:
操作步骤:将上面打好的apk放在PythonTool文件夹下面,和MultiChannelBuildTool.py同级,看图:
注意:MultiChannelBuildTool.py这个文件请选择打开方式是Python,看前面的小图标(还有一种打开方法:直接命令行执行)。直接双击运行MultiChannelBuildTool.py这个脚本,真的是一眨眼功夫,包就出来了:
打出的apk包全部在output_app-release文件夹下面。在写下文之前,这里还是提一下,这个多渠道打包默认的渠道名是在info这个文件夹下面的channel.txt中,我这里面的内容是这样的:
按照这个格式,任意写需要打包的渠道名即可。回到output_app-release文件夹,对应打出的包:
最后拿出手机来测试下我上面所说的猜想:如果我现在安装91com的包,按道理来说,OtherActivity中的button就应该显示91com,安装xiaomi的包,OtherActivity中的button就应该显示xiaomi,以此类推。好,看下效果吧。
后面也试了一下其他apk,都是准确的把对应的渠道名显示出来了。OK!到此,基本就是这样了,也就是说,channel.txt中对应的渠道名打到包里面了。在实际项目中,可以用这里拿到的渠道去做更多的事情,这个就自由发挥了。谢谢大家能看到这里!也谢谢能将技术分享出来的大神们,我只是你们的代码搬运工。还有,写到这,再啰嗦几句:不管是什么知识,看到和知道并不一定你就得到,想得到很简单,动手实现试试就行,很多知识只有亲自做一遍才有底,实践出真知!谢谢大家!