Android PC端实现apk多渠道打包

      最近查看一下电脑资料,找到一个印象很深刻的项目。记得几年前刚进入公司两个星期,第一次接触游戏SDK玩意,还在熟悉代码的过程中,产品经理开了个需求会,意思是现在和三七互娱在对接一个游戏,公司想在PC端实现多渠道打包和替换背景图(目前背景图是拉伸的,要替换三七互娱给的背景图),就是运营人员在PC端上能操作多渠道打包。类似易接那样。我脑海里十万个为什么,什么鬼?什么东西?什么情况?这不是要C语言来实现的吗?不是要C来生成exe执行程序吗?按我的经验我实现不了,产品经理回复,我不管,只要很简单实现就可以了。   

    回到座位上脑袋一片空白,完全没有思路。那时很想放弃,但后来想想,还是尝试一下。 

    想到要解决的问题

  1. java如何在PC端可运行?
  2. 操作界面如何绘画?
  3. 如何实现替换渠道号和背景图?

    通过求助百度,大致有了思路

  1. eclipse中打包成jar包可选择可运行jar。(习惯使用Android Studio开发,eclipse使用不熟悉,没办法,回归到eclipse)   
  2. java中有个swing的界面库(java中不经常使用,几乎抛弃了) 
  3. 幸好渠道文件是放在asset中,不被编译成二进制,只要将asset文件下的渠道文件替换渠道号就可,那么整体就是解包--替换渠道号和背景图-->打包并签名。

以下是部分实现代码,希望给遇到类似的问题的同学们提供个思路。

绘制页面代码:

private static final long serialVersionUID = 1L;

	private JTextField apkUploadName;
	private JButton upLoadBtn;// 上传按钮
	private JTextField apkFilePath;// 显示上传路径

	private JTextField channelName;
	private JTextField channelField;
	private JButton changeChannelBtn;// 更改渠道号

	private JTextField appidTextField;// 修改appid

	private JTextField appKeyTextField;// 修改appKey

	private JTextField bgField;
	private JButton changeBgImageBtn;// 更改背景图
	private JTextField bgTextUrlField;

	private JTextField splashText;
	private JButton changeSplashImageBtn;// 更改背景图
	private JTextField splashTextUrlField;

	private JButton signButton;// 打包签名
	private JProgressBar progressBar;
	
	private JTextField signTextUrl;// 路径
	private JTextField signText;// 签名路径
	
	private JButton sureBtn;// 确认按钮

	private JButton canclBtn;// 取消按钮

	public static final int WIDTH = 800;
	public static final int HEIGTH = 600;

	private JTextField appid;
	private JTextField appKey;
	private ArrayList<String> channelkey = new ArrayList<String>();

	private JPanel biggerJPanel;

	/*public static void main(String[] args) {
		ToolDemo toolDemo = new ToolDemo();
		toolDemo.setVisible(true);
	}*/

	public ToolDemo() {
		super("游戏母包分包工具");
		this.setSize(WIDTH, HEIGTH);
		this.setLocation(500, 300); // 设置窗体在屏幕的位置
		Container contentPane = getContentPane();
		contentPane.setBackground(Color.CYAN);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 设置JVM退出后,窗体的退出属性
		
		initView();
		initJPane();
	}

	private void initView() {
		
		apkUploadName=new JTextField(Constants.APKUPLOADNAME);
		apkUploadName.setBounds(50, 50, 90, 25);
		setStyle(apkUploadName);
		
		apkFilePath = new JTextField();
		apkFilePath.setHorizontalAlignment(JTextField.LEFT);
		apkFilePath.setBounds(150, 50, 450, 25);

		upLoadBtn = new JButton(Constants.UPLOADAPK);
		upLoadBtn.addActionListener(this);
		upLoadBtn.setBounds(620, 50, 80, 25);
		
		channelName = new JTextField(Constants.CHANGECHANNEL);
		channelName.setBounds(50, 100, 80, 25);
		setStyle(channelName);

		channelField = new JTextField();
		channelField.setEditable(true);
		channelField.setBounds(150, 100, 450, 25);

		changeChannelBtn = new JButton(Constants.CHANGECHANNEL);
		changeChannelBtn.addActionListener(this);
		changeChannelBtn.setBounds(620, 100, 80, 25);

		appid = new JTextField(Constants.APPID);
		appid.setBounds(50, 150, 50, 25);
		setStyle(appid);

		appidTextField = new JTextField();
		appidTextField.setEditable(true);
		appidTextField.setBounds(130, 150, 100, 25);

		appKey = new JTextField(Constants.APPKEY);
		appKey.setBounds(250, 150, 60, 25);
		setStyle(appKey);

		appKeyTextField = new JTextField();
		appKeyTextField.setEditable(true);
		appKeyTextField.setBounds(320, 150, 200, 25);

		bgField = new JTextField(Constants.UPDATEBACKGROUD);
		bgField.setBounds(50, 200, 80, 25);
		setStyle(bgField);

		bgTextUrlField = new JTextField();
		bgTextUrlField.setHorizontalAlignment(JTextField.LEFT);
		bgTextUrlField.setBounds(150, 200, 450, 25);

		changeBgImageBtn = new JButton(Constants.LIULAN);
		changeBgImageBtn.addActionListener(this);
		changeBgImageBtn.setBounds(620, 200, 80, 25);

		splashText = new JTextField(Constants.UPDATESPLASH);
		splashText.setBounds(50, 250, 80, 25);
		setStyle(splashText);

		splashTextUrlField = new JTextField();
		splashTextUrlField.setHorizontalAlignment(JTextField.LEFT);
		splashTextUrlField.setBounds(150, 250, 450, 25);

		changeSplashImageBtn = new JButton(Constants.LIULANIMAGE);
		changeSplashImageBtn.addActionListener(this);
		changeSplashImageBtn.setBounds(620, 250, 80, 25);

		signText = new JTextField(Constants.SIGNURL);
		signText.setBounds(50, 300, 80, 25);
		setStyle(signText);

		signTextUrl = new JTextField();
		signTextUrl.setHorizontalAlignment(JTextField.LEFT);
		signTextUrl.setBounds(150, 300, 450, 25);

		signButton = new JButton(Constants.CHOOSE);
		signButton.addActionListener(this);
		signButton.setBounds(620, 300, 80, 25);
		
		progressBar=new JProgressBar();
		progressBar.setBounds(150, 310, 450, 30);
	    progressBar.setMinimum(0);
	    progressBar.setMaximum(100);
	    progressBar.setStringPainted(true);
	    progressBar.setBorderPainted(true);
        progressBar.setUI(new MetalProgressBarUI());
        progressBar.setBackground(Color.CYAN);
        progressBar.setForeground(Color.BLUE);
	    
	    
		sureBtn = new JButton(Constants.SURE);
		sureBtn.addActionListener(this);
		sureBtn.setBounds(200, 400, 100, 25);

		canclBtn = new JButton(Constants.CANCLE);
		canclBtn.addActionListener(this);
		canclBtn.setBounds(400, 400, 100, 25);
	}

	private void initJPane() {
		biggerJPanel = new JPanel();
		biggerJPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		//biggerJPanel.setBackground(new Color(0, 0, 0,1));
		setContentPane(biggerJPanel);
		biggerJPanel.setLayout(null);

		biggerJPanel.add(apkUploadName);
		biggerJPanel.add(apkFilePath);
		biggerJPanel.add(upLoadBtn);
		biggerJPanel.add(changeChannelBtn);
		biggerJPanel.add(channelField);
		biggerJPanel.add(channelName);
		biggerJPanel.add(appidTextField);
		biggerJPanel.add(appKeyTextField);
		biggerJPanel.add(appid);
		biggerJPanel.add(appKey);
		biggerJPanel.add(bgField);
		biggerJPanel.add(bgTextUrlField);
		biggerJPanel.add(changeBgImageBtn);
		biggerJPanel.add(splashText);
		biggerJPanel.add(changeSplashImageBtn);
		biggerJPanel.add(splashTextUrlField);
		/*biggerJPanel.add(signButton);
		biggerJPanel.add(signText);
		biggerJPanel.add(signTextUrl);*/
		
		//biggerJPanel.add(progressBar);
		biggerJPanel.add(sureBtn);
		biggerJPanel.add(canclBtn);
	}

	private void setStyle(JTextField text) {
		text.setBorder(null);
		text.setHorizontalAlignment(JTextField.LEFT);
		text.setFont(new Font("楷体", Font.PLAIN, 16));
		text.setEditable(false);
	}

 解包:

// 解压
	@SuppressWarnings("rawtypes")
	public static void unZip(String fileName, String filePath) throws Exception {
		ZipFile zipFile = new ZipFile(fileName);
		Enumeration emu = zipFile.entries();

		while (emu.hasMoreElements()) {
			ZipEntry entry = (ZipEntry) emu.nextElement();
			if (entry.isDirectory()) {
				new File(filePath + entry.getName()).mkdirs();
				continue;
			}
			BufferedInputStream bis = new BufferedInputStream(
					zipFile.getInputStream(entry));

			File file = new File(filePath + entry.getName());
			File parent = file.getParentFile();
			if (parent != null && (!parent.exists())) {
				parent.mkdirs();
			}
			FileOutputStream fos = new FileOutputStream(file);
			BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER);

			byte[] buf = new byte[BUFFER];
			int len = 0;
			while ((len = bis.read(buf, 0, BUFFER)) != -1) {
				fos.write(buf, 0, len);
			}
			bos.flush();
			bos.close();
			bis.close();
		}
		zipFile.close();
	}

读取文件和修改文件

// 读取渠道文件
	public static void setChannelFile(String txtPath,ArrayList<String> channelkey) {
		File f = new File(txtPath);
		if (f.exists() && f.isFile()) {
			try {
				BufferedReader br = new BufferedReader(new FileReader(f));
				String line = null;
				while ((line = br.readLine()) != null) {
					channelkey.add(line.trim());
				}
				System.out.println(channelkey.toString());
			} catch (Exception e) {
				e.printStackTrace();
				JOptionPane.showMessageDialog(null, "渠道文件有误", "错误", JOptionPane.ERROR_MESSAGE);
			}
		}
	}


	//读取、修改、写出txt文件
	public static void updateChannelkey(String path, String key)throws Exception {
		BufferedReader br = new BufferedReader(new FileReader(path));
		String lineKey = null;
		StringBuffer sb = new StringBuffer();
		while ((lineKey = br.readLine()) != null) {
			System.out.println(lineKey);
			lineKey = lineKey.replaceAll(lineKey.trim(), key);
			System.out.println(lineKey);
			sb.append(lineKey + "\n");
		}
		br.close();

		FileWriter fw = new FileWriter(path);
		fw.write(sb.toString());
		fw.close();
	}

最后打包和签名

//打包及签名
	public static void compressAndSignApk(StringBuffer buffer, String signPath,
			String apkSrcPath, String apkName, String prefixName,
			String targetPath, String resultPath, String key) throws Exception {
		// 判断创建文件夹
		File targetFile = new File(targetPath);
		if (!targetFile.exists()) {
			targetFile.mkdir();
		}

        //打包
		ZipUtils.compress(apkSrcPath+ Constants.SOURE_PATH_NAME + prefixName,targetPath + apkName);

		// 判断创建文件夹
		File resultFile = new File(resultPath);
		if (!resultFile.exists()) {
			resultFile.mkdir();
		}

		// 组合签名命令
		String apkSign = apkName.split(".apk")[0] + "_signed_"+ key + ".apk";
		buffer.setLength(0);
		buffer.append("cmd.exe /c jarsigner -digestalg SHA1 -sigalg MD5withRSA -tsa https://timestamp.geotrust.com/tsa -keystore ")
			.append(signPath).append(" -storepass ")
			.append(Constants.SIGN_PASSWORD)
			.append(" -signedjar ").append(resultPath)
			.append(apkSign).append(" ") // 签名保存路径应用名称
			.append(targetPath).append(apkName).append(" ") // 打包保存路径应用名称
			.append(Constants.SIGN_NAME);
		System.out.println(buffer.toString());
		if (buffer.toString()!=null) {
			CommanUtils.runCmd(buffer.toString());
		}else {
			JOptionPane.showMessageDialog(null, "签名有误", "错误", JOptionPane.ERROR_MESSAGE);
		}
	}

// 执行cmd命令
	public static void runCmd(String cmd) {
		Runtime rt = Runtime.getRuntime();
		try {
			Process p = rt.exec(cmd,null);
			// p.waitFor();
			BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
				String msg = null;
				while ((msg = br.readLine()) != null) {
					System.out.println(msg);
				}
			/*if(p.waitFor()!=0){
				JOptionPane.showInputDialog("打包失败!");
			}*/
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(null, "cmd命令运行错误", "错误", JOptionPane.ERROR_MESSAGE);
		}
	}

最后说一下,用了SwingSets2(BeautyEyeLNFDemo).jar实现外观精致。实测打包50个,大概用了15分钟(系甘上下)。我不是专科出生的,没多大经验,能做出这样的一个需求,自己也觉得不可思议,但最终产品没用这个工具。希望这样的实现思路能给遇到类似的问题的伙伴们提供思路。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值