关于打Android aar离线包的一些经验分享
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于打Android aar离线包的一些经验分享相关的知识,希望对你有一定的参考价值。
参考技术A 几经思考后,本来想手动把a,b,c那几个库编译成jar放到aar的lib里,但是找到那些a,b,c库一看他们又分别依赖了公司另外的几个库d,e,f,顿时头大了,真要自己一个个手动编译就头大了,后来在网上找了一圈发现一个插件是解决这种难题的完美方案。就是fat-aar(胖子aar),GitHub地址:该插件提供的功能主要是帮我们把sdk的依赖库集成到aar里,使用上还需自行灵活选择哪些依赖库需要集成进aar,哪些不需要,比如我在打完全量依赖的aar后(配置transitive为true,只embed标记公司的库依赖,三方库不打标记)就发现会出现很多类/模块重复,一看都是官方的一些库文件,原因是全量打包会把所有支付Sdk里embed标记的库依赖的依赖(树结构遍历一直到底)都集成进aar,这样肯定会出现很多重复的模块/类。
所以后来又打了一个只引入直属依赖jar包的aar((配置transitive为false,也是只embed标记公司的库依赖,三方库不打标记),这样就只会把支付Sdk里的embed标记依赖库集成进aar,而不会继续遍历下去集成更底层的依赖,如此确实解决了模块/类冲突的问题,但是因为没有把所有的依赖集成进aar,使用的时候会报很多ClassNotFound的错误。
在这里卡了很久,虽然知道问题原因,但是处理起来着实麻烦,好在fat-aar插件打包aar的时候把大部分直属/公司库依赖都是放在classes.jar里,而很多知名三方/android官方依赖放在libs目录下,如此,我便想到可以把全量aar里的classes.jar文件里的com包(里面大都是公司的依赖jar)复制替换掉直属依赖aar包里面的com包,删掉android和androidx包,最后使用修改过的直属依赖aar放到demo工程libs里跑起来后,还是报了一些知名三方库(retrofit,gson等)没有找到的错误,这都是预期会出现的问题,在demo里重新依赖一下即可。
到此,我们提供的支付Sdk的aar包里面包含的基本是我们公司自己的库相关集成,知名的三方库让使用者自行添加依赖即可,这样对集成方也更友好,因为他们自己的工程很多可能会自行集成那些知名三方库,这样就不会出现包名/类冲突的问题,但是需要集成哪些知名 三方库需要告知集成者。(期间遇到因为公司加密系统导致360压缩编辑aar和jar包时损坏文件,后面改用rar压缩解决了问题)
unity打aar包工具
需求:
unity将游戏导出android工程之后,打成aar包的工具
第一种:
高版本的unity导出的android工程是android studio版的,那么打成aar的流程就是
1.build.gradle文件中把apply plugin: ‘com.android.application‘改成apply plugin: ‘com.android.library‘ 2.build.gradle文件中buildToolsVersion改为25.0.2 3.注释掉applicationId这一行 4.清单文件AndroidManifest.xml中启动Activity,一般是UnityPlayerActiity,标签内全部删除 5.src.java下类UnityPlayerActiity共三个都删除 6.然后在主目录下执行命令gradlew.bat assembleDebug生成aar
把上述流程做成java自动的工具,代码如下
package com.jinkejoy.build_aar; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; public class ASBuildAarFile { private static final String CACHE_PATH = "C:\\build-apk-path.properties"; private JFrame jFrame; private JTextField sourcePath_text; private JButton sourcePath_button; private File sourceFile; private JTextField output_text; private JButton output_button; private File outputFile; private JTextField sdk_text; private JButton sdk_button; private File sdkFile; private JTextField ndk_text; private JButton ndk_button; private File ndkFile; private JButton buildAar_button; private JButton outputAar_button; public static void main(String[] args) { new ASBuildAarFile(); } public ASBuildAarFile() { openFileWindow(); } private void openFileWindow() { jFrame = new JFrame(); jFrame.setTitle("将android工程打成aar"); jFrame.setBounds(500, 500, 700, 200); jFrame.setVisible(true); FlowLayout layout = new FlowLayout(); layout.setAlignment(FlowLayout.LEFT); //选择文件 JLabel filePath_label = new JLabel("工程路径:"); sourcePath_text = new JTextField(50); sourcePath_button = new JButton("浏览"); //输出路径 JLabel output_label = new JLabel("出包路径:"); output_text = new JTextField(50); output_button = new JButton("浏览"); //sdk JLabel sdk_label = new JLabel("本地sdk路径:"); sdk_text = new JTextField(48); sdk_button = new JButton("浏览"); //ndk JLabel ndk_label = new JLabel("本地ndk路径(sdk路径下):"); ndk_text = new JTextField(42); ndk_button = new JButton("浏览"); //构建 buildAar_button = new JButton("构建aar"); outputAar_button = new JButton("弹出aar(构建aar成功后再点)"); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setLayout(layout); jFrame.setResizable(false); jFrame.add(filePath_label); jFrame.add(sourcePath_text); jFrame.add(sourcePath_button); jFrame.add(output_label); jFrame.add(output_text); jFrame.add(output_button); jFrame.add(sdk_label); jFrame.add(sdk_text); jFrame.add(sdk_button); jFrame.add(ndk_label); jFrame.add(ndk_text); jFrame.add(ndk_button); jFrame.add(buildAar_button); jFrame.add(outputAar_button); choosePath(); outputPath(); sdkPath(); ndkPath(); buildAar(); outputAar(); getCachePath(); } public void choosePath() { sourcePath_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); sourceFile = chooser.getSelectedFile(); sourcePath_text.setText(sourceFile.getAbsolutePath().toString()); } }); } private void outputPath() { output_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); outputFile = chooser.getSelectedFile(); output_text.setText(outputFile.getAbsolutePath().toString()); } }); } private void sdkPath() { sdk_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); sdkFile = chooser.getSelectedFile(); sdk_text.setText(sdkFile.getAbsolutePath().toString()); } }); } private void ndkPath() { ndk_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); ndkFile = chooser.getSelectedFile(); ndk_text.setText(ndkFile.getAbsolutePath().toString()); } }); } private void buildAar() { buildAar_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { buildAarImpl(); } }); } private void outputAar() { outputAar_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { outputAarImpl(sourcePath_text.getText().toString()); } }); } private void cachePath() { String cache = "sourcePath=" + sourcePath_text.getText().toString().replace("\\", "\\\\") + " " + "outputPath=" + output_text.getText().toString().replace("\\", "\\\\") + " " + "sdkPath=" + sdk_text.getText().toString().replace("\\", "\\\\") + " " + "ndkPath=" + ndk_text.getText().toString().replace("\\", "\\\\") + " "; File cacheFile = new File(CACHE_PATH); if (!cacheFile.exists()) { try { cacheFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } try { FileOutputStream fop = new FileOutputStream(cacheFile); fop.write(cache.getBytes()); fop.flush(); fop.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void getCachePath() { File cacheFile = new File(CACHE_PATH); if (cacheFile.exists()) { try { FileInputStream fip = new FileInputStream(cacheFile); Properties properties = new Properties(); properties.load(fip); Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Object, Object> entry = iterator.next(); switch (entry.getKey().toString()) { case "sourcePath": sourcePath_text.setText(entry.getValue().toString()); break; case "outputPath": output_text.setText(entry.getValue().toString()); break; case "sdkPath": sdk_text.setText(entry.getValue().toString()); break; case "ndkPath": ndk_text.setText(entry.getValue().toString()); break; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } private void buildAarImpl() { if (checkInput()) return; cachePath(); String filePath = sourcePath_text.getText().toString(); findUpdateFile(filePath); gradleBuildAar(); } private void gradleBuildAar() { String command = "cmd /c start gradle clean assembleDebug"; File cmdPath = new File(sourcePath_text.getText().toString()); Runtime runtime = Runtime.getRuntime(); try { Process process = runtime.exec(command, null, cmdPath); } catch (IOException e) { e.printStackTrace(); } } private void outputAarImpl(String filePath) { if (checkInput()) return; findAarFile(filePath); String command = "cmd /k start " + output_text.getText().toString(); Runtime runtime = Runtime.getRuntime(); try { runtime.exec(command); } catch (IOException e) { e.printStackTrace(); } } private void findAarFile(String filePath) { File file = new File(filePath); if (!file.exists()) { return; } File[] files = file.listFiles(); for (File outputFile : files) { if (outputFile.isDirectory()) { findAarFile(outputFile.getAbsolutePath()); } else { String fileName = outputFile.getName().toString(); if (fileName.endsWith(".aar")) { String time = timeStamp2Date(String.valueOf(System.currentTimeMillis())); String aarName = fileName.substring(0, fileName.length() - 4); File aarFile = new File(output_text.getText().toString() + "\\" + aarName + time + ".aar"); outputFile.renameTo(aarFile); } } } } private void findUpdateFile(String filePath) { File file = new File(filePath); if (!file.exists()) { return; } File[] files = file.listFiles(); for (File updateFile : files) { if (updateFile.isDirectory()) { findUpdateFile(updateFile.getAbsolutePath()); } else { switch (updateFile.getName().toString()) { case "build.gradle": updateBuildGradle(updateFile.getAbsolutePath()); break; case "AndroidManifest.xml": updateManifestFile(updateFile.getAbsolutePath()); break; case "local.properties": updateSdkFile(updateFile.getAbsolutePath()); break; case "UnityPlayerActivity.java": case "UnityPlayerNativeActivity.java": case "UnityPlayerProxyActivity.java": updateFile.delete(); break; } } } } private void updateSdkFile(String filePath) { try { RandomAccessFile sdkFile = new RandomAccessFile(filePath + "\\local.properties", "rw"); String line; long lastPoint = 0; while ((line = sdkFile.readLine()) != null) { final long point = sdkFile.getFilePointer(); if (line.contains("sdk.dir")) { String s = line.substring(0); String sdkStr = sdk_text.getText().toString(); String sdkPan = sdkStr.substring(0, 1); sdkStr = sdkStr.substring(1).replace("\\", "\\\\"); String ndkStr = ndk_text.getText().toString(); String ndkPan = ndkStr.substring(0, 1); ndkStr = ndkStr.substring(1).replace("\\", "\\\\"); String replaceStr = "sdk.dir=" + sdkPan + "\\" + sdkStr + " " + "ndk.dir=" + ndkPan + "\\" + ndkStr + " "; String str = line.replace(s, replaceStr); sdkFile.seek(lastPoint); sdkFile.writeBytes(str); } lastPoint = point; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void updateManifestFile(String filePath) { try { RandomAccessFile manifestFile = new RandomAccessFile(filePath, "rw"); String line; long lastPoint = 0; while ((line = manifestFile.readLine()) != null) { final long ponit = manifestFile.getFilePointer(); if (line.contains("<activity") && line.contains("UnityPlayerActivity") && !line.contains("<!--<activity")) { String str = line.replace("<activity", "<!--<activity"); manifestFile.seek(lastPoint); manifestFile.writeBytes(str); } if (line.contains("</activity>") && !line.contains("</activity>-->")) { String str = line.replace("</activity>", "</activity>--> "); manifestFile.seek(lastPoint); manifestFile.writeBytes(str); } lastPoint = ponit; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void updateBuildGradle(String filePath) { try { RandomAccessFile buildGradleFile = new RandomAccessFile(filePath, "rw"); String line; long lastPoint = 0; while ((line = buildGradleFile.readLine()) != null) { final long ponit = buildGradleFile.getFilePointer(); if (line.contains("classpath ‘com.android.tools.build:gradle")) { String s = line.substring(line.indexOf("classpath")); String str = line.replace(s, "classpath ‘com.android.tools.build:gradle:2.3.0‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("com.android.application")) { String str = line.replace("‘com.android.application‘", "‘com.android.library‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("compileSdkVersion") && !line.contains("compileSdkVersion 25")) { String s = line.substring(line.indexOf("compileSdkVersion")).toString(); String str = line.replace(s, "compileSdkVersion 25 "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("buildToolsVersion") && !line.contains("buildToolsVersion ‘25.0.2‘")) { String s = line.substring(line.indexOf("buildToolsVersion")).toString(); String str = line.replace(s, "buildToolsVersion ‘25.0.2‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("targetSdkVersion") && !line.contains("targetSdkVersion 25")) { String s = line.substring(line.indexOf("targetSdkVersion")).toString(); String str = line.replace(s, "targetSdkVersion 25 "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("applicationId") && !line.contains("//applicationId")) { String s = line.substring(line.indexOf("applicationId")).toString(); String str = line.replace(s, "//" + s + " "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } lastPoint = ponit; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private boolean checkInput() { if ("".equals(sourcePath_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入源工程文件路径"); return true; } if ("".equals(output_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入apk输出路径"); return true; } if ("".equals(sdk_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入本地sdk路径"); return true; } if ("".equals(ndk_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入本地ndk路径"); return true; } return false; } public static String timeStamp2Date(String time) { Long timeLong = Long.parseLong(time); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");//要转换的时间格式 Date date; try { date = sdf.parse(sdf.format(timeLong)); return sdf.format(date); } catch (ParseException e) { e.printStackTrace(); return null; } } }
方法名写的很清楚,我就不加注释了。
jar包打成可运行程序参考android studio打可执行jar包
第二种:
低版本的unity导出的android工程是Eclipse版的
Eclipse版的android工程和android studio版的android工程还是有不小区别的,所以我增加了一个母包,用于把eclipse版变成android studio版,代码如下
package com.jinkejoy.build_aar; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; public class EcBuildAarFile { private static final String CACHE_PATH = "C:\\build-apk-path.properties"; private JFrame jFrame; private JTextField sourcePath_text; private JButton sourcePath_button; private File sourceFile; private JTextField output_text; private JButton output_button; private File outputFile; private JTextField sdk_text; private JButton sdk_button; private File sdkFile; private JTextField ndk_text; private JButton ndk_button; private File ndkFile; private JTextField main_text; private JButton main_button; private File mainFile; private JButton buildAar_button; private JButton outputAar_button; public static void main(String[] args) { new EcBuildAarFile(); } public EcBuildAarFile() { openFileWindow(); } private void openFileWindow() { jFrame = new JFrame(); jFrame.setTitle("将android工程打成aar"); jFrame.setBounds(500, 500, 700, 250); jFrame.setVisible(true); FlowLayout layout = new FlowLayout(); layout.setAlignment(FlowLayout.LEFT); //选择文件 JLabel filePath_label = new JLabel("工程路径:"); sourcePath_text = new JTextField(50); sourcePath_button = new JButton("浏览"); //输出路径 JLabel output_label = new JLabel("出包路径:"); output_text = new JTextField(50); output_button = new JButton("浏览"); //sdk JLabel sdk_label = new JLabel("本地sdk路径:"); sdk_text = new JTextField(48); sdk_button = new JButton("浏览"); //ndk JLabel ndk_label = new JLabel("本地ndk路径(sdk路径下):"); ndk_text = new JTextField(42); ndk_button = new JButton("浏览"); //母包 JLabel main_label = new JLabel("本地母包文件路径:"); main_text = new JTextField(45); main_button = new JButton("浏览"); //构建 buildAar_button = new JButton("构建aar"); outputAar_button = new JButton("弹出aar(构建aar成功后再点)"); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setLayout(layout); jFrame.setResizable(false); jFrame.add(filePath_label); jFrame.add(sourcePath_text); jFrame.add(sourcePath_button); jFrame.add(output_label); jFrame.add(output_text); jFrame.add(output_button); jFrame.add(sdk_label); jFrame.add(sdk_text); jFrame.add(sdk_button); jFrame.add(ndk_label); jFrame.add(ndk_text); jFrame.add(ndk_button); jFrame.add(main_label); jFrame.add(main_text); jFrame.add(main_button); jFrame.add(buildAar_button); jFrame.add(outputAar_button); choosePath(); outputPath(); sdkPath(); ndkPath(); mainPath(); buildAar(); outputAar(); getCachePath(); } public void choosePath() { sourcePath_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); sourceFile = chooser.getSelectedFile(); sourcePath_text.setText(sourceFile.getAbsolutePath().toString()); } }); } private void outputPath() { output_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); outputFile = chooser.getSelectedFile(); output_text.setText(outputFile.getAbsolutePath().toString()); } }); } private void sdkPath() { sdk_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); sdkFile = chooser.getSelectedFile(); sdk_text.setText(sdkFile.getAbsolutePath().toString()); } }); } private void ndkPath() { ndk_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); ndkFile = chooser.getSelectedFile(); ndk_text.setText(ndkFile.getAbsolutePath().toString()); } }); } private void mainPath() { main_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); mainFile = chooser.getSelectedFile(); main_text.setText(mainFile.getAbsolutePath().toString()); } }); } private void buildAar() { buildAar_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { buildAarImpl(); } }); } private void outputAar() { outputAar_button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { outputAarImpl(main_text.getText().toString()); } }); } private void cachePath() { String cache = "sourcePath=" + sourcePath_text.getText().toString().replace("\\", "\\\\") + " " + "outputPath=" + output_text.getText().toString().replace("\\", "\\\\") + " " + "sdkPath=" + sdk_text.getText().toString().replace("\\", "\\\\") + " " + "ndkPath=" + ndk_text.getText().toString().replace("\\", "\\\\") + " " + "mainPath=" + main_text.getText().toString().replace("\\", "\\\\"); File cacheFile = new File(CACHE_PATH); if (!cacheFile.exists()) { try { cacheFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } try { FileOutputStream fop = new FileOutputStream(cacheFile); fop.write(cache.getBytes()); fop.flush(); fop.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void getCachePath() { File cacheFile = new File(CACHE_PATH); if (cacheFile.exists()) { try { FileInputStream fip = new FileInputStream(cacheFile); Properties properties = new Properties(); properties.load(fip); Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Object, Object> entry = iterator.next(); switch (entry.getKey().toString()) { case "sourcePath": sourcePath_text.setText(entry.getValue().toString()); break; case "outputPath": output_text.setText(entry.getValue().toString()); break; case "sdkPath": sdk_text.setText(entry.getValue().toString()); break; case "ndkPath": ndk_text.setText(entry.getValue().toString()); break; case "mainPath": main_text.setText(entry.getValue().toString()); break; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } private void buildAarImpl() { if (checkInput()) return; cachePath(); createAs(); findUpdateFile(main_text.getText().toString()); gradleBuildAar(); } private void createAs() { String sourcePath = sourcePath_text.getText().toString(); String mainPath = main_text.getText().toString(); //assets String assets = sourcePath + "\\assets"; String newAssets = mainPath + "\\app\\src\\main\\assets"; copyFolder(assets, newAssets); //unity-classes.jar String unity = sourcePath + "\\libs\\unity-classes.jar"; String newUnity = mainPath + "\\app\\libs\\unity-classes.jar"; copyFolder(unity, newUnity); //libs String libs = sourcePath + "\\libs"; String jniLibs = mainPath + "\\app\\src\\main\\jniLibs"; copyFolder(libs, jniLibs); //res String res = sourcePath + "\\res"; String newRes = mainPath + "\\app\\src\\main\\res"; copyFolder(res, newRes); //src String src = sourcePath + "\\src"; String java = mainPath + "\\app\\src\\main\\java"; copyFolder(src, java); //AndroidManifest.xml String manifest = sourcePath + "\\AndroidManifest.xml"; String newManifest = mainPath + "\\app\\src\\main\\AndroidManifest.xml"; copyFolder(manifest, newManifest); } public static void copyFolder(String oldPath, String newPath) { try { // 如果文件夹不存在,则建立新文件夹 (new File(newPath)).mkdirs(); // 读取整个文件夹的内容到file字符串数组,下面设置一个游标i,不停地向下移开始读这个数组 File filelist = new File(oldPath); String[] file = filelist.list(); // 要注意,这个temp仅仅是一个临时文件指针 // 整个程序并没有创建临时文件 File temp = null; for (int i = 0; i < file.length; i++) { // 如果oldPath以路径分隔符/或者结尾,那么则oldPath/文件名就可以了 // 否则要自己oldPath后面补个路径分隔符再加文件名 // 谁知道你传递过来的参数是f:/a还是f:/a/啊? if (oldPath.endsWith(File.separator)) { temp = new File(oldPath + file[i]); } else { temp = new File(oldPath + File.separator + file[i]); } // 如果游标遇到文件 if (temp.isFile()) { FileInputStream input = new FileInputStream(temp); // 复制并且改名 FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString()); byte[] bufferarray = new byte[1024 * 64]; int prereadlength; while ((prereadlength = input.read(bufferarray)) != -1) { output.write(bufferarray, 0, prereadlength); } output.flush(); output.close(); input.close(); } // 如果游标遇到文件夹 if (temp.isDirectory()) { copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]); } } } catch (Exception e) { System.out.println("复制整个文件夹内容操作出错"); } } private void gradleBuildAar() { String command = "cmd /c start gradle clean assembleDebug"; File cmdPath = new File(main_text.getText().toString()); Runtime runtime = Runtime.getRuntime(); try { Process process = runtime.exec(command, null, cmdPath); } catch (IOException e) { e.printStackTrace(); } } private void outputAarImpl(String filePath) { if (checkInput()) return; findAarFile(filePath); String command = "cmd /k start " + output_text.getText().toString(); Runtime runtime = Runtime.getRuntime(); try { runtime.exec(command); } catch (IOException e) { e.printStackTrace(); } } private void findAarFile(String filePath) { File file = new File(filePath); if (!file.exists()) { return; } File[] files = file.listFiles(); for (File outputFile : files) { if (outputFile.isDirectory()) { findAarFile(outputFile.getAbsolutePath()); } else { String fileName = outputFile.getName().toString(); if (fileName.endsWith(".aar")) { String time = timeStamp2Date(String.valueOf(System.currentTimeMillis())); String aarName = fileName.substring(0, fileName.length() - 4); File aarFile = new File(output_text.getText().toString() + "\\" + aarName + time + ".aar"); outputFile.renameTo(aarFile); } } } } private void findUpdateFile(String filePath) { File file = new File(filePath); if (!file.exists()) { return; } File[] files = file.listFiles(); for (File updateFile : files) { if (updateFile.isDirectory()) { findUpdateFile(updateFile.getAbsolutePath()); } else { switch (updateFile.getName().toString()) { case "build.gradle": updateBuildGradle(updateFile.getAbsolutePath()); break; case "AndroidManifest.xml": updateManifestFile(updateFile.getAbsolutePath()); break; case "local.properties": updateSdkFile(updateFile.getAbsolutePath()); break; case "UnityPlayerActivity.java": case "UnityPlayerNativeActivity.java": case "UnityPlayerProxyActivity.java": updateFile.delete(); break; } } } } private void updateSdkFile(String filePath) { try { RandomAccessFile sdkFile = new RandomAccessFile(filePath + "\\local.properties", "rw"); String line; long lastPoint = 0; while ((line = sdkFile.readLine()) != null) { final long point = sdkFile.getFilePointer(); if (line.contains("sdk.dir")) { String s = line.substring(0); String sdkStr = sdk_text.getText().toString(); String sdkPan = sdkStr.substring(0, 1); sdkStr = sdkStr.substring(1).replace("\\", "\\\\"); String ndkStr = ndk_text.getText().toString(); String ndkPan = ndkStr.substring(0, 1); ndkStr = ndkStr.substring(1).replace("\\", "\\\\"); String replaceStr = "sdk.dir=" + sdkPan + "\\" + sdkStr + " " + "ndk.dir=" + ndkPan + "\\" + ndkStr + " "; String str = line.replace(s, replaceStr); sdkFile.seek(lastPoint); sdkFile.writeBytes(str); } lastPoint = point; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void updateManifestFile(String filePath) { try { RandomAccessFile manifestFile = new RandomAccessFile(filePath, "rw"); String line; long lastPoint = 0; while ((line = manifestFile.readLine()) != null) { final long ponit = manifestFile.getFilePointer(); if (line.contains("<activity") && line.contains("UnityPlayerActivity") && !line.contains("<!--<activity")) { String str = line.replace("<activity", "<!--<activity"); manifestFile.seek(lastPoint); manifestFile.writeBytes(str); } if (line.contains("</activity>") && !line.contains("</activity>-->")) { String str = line.replace("</activity>", "</activity>--> "); manifestFile.seek(lastPoint); manifestFile.writeBytes(str); } lastPoint = ponit; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void updateBuildGradle(String filePath) { try { RandomAccessFile buildGradleFile = new RandomAccessFile(filePath, "rw"); String line; long lastPoint = 0; while ((line = buildGradleFile.readLine()) != null) { final long ponit = buildGradleFile.getFilePointer(); if (line.contains("classpath ‘com.android.tools.build:gradle")) { String s = line.substring(line.indexOf("classpath")); String str = line.replace(s, "classpath ‘com.android.tools.build:gradle:2.3.0‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("com.android.application")) { String str = line.replace("‘com.android.application‘", "‘com.android.library‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("compileSdkVersion") && !line.contains("compileSdkVersion 25")) { String s = line.substring(line.indexOf("compileSdkVersion")).toString(); String str = line.replace(s, "compileSdkVersion 25 "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("buildToolsVersion") && !line.contains("buildToolsVersion ‘25.0.2‘")) { String s = line.substring(line.indexOf("buildToolsVersion")).toString(); String str = line.replace(s, "buildToolsVersion ‘25.0.2‘ "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("targetSdkVersion") && !line.contains("targetSdkVersion 25")) { String s = line.substring(line.indexOf("targetSdkVersion")).toString(); String str = line.replace(s, "targetSdkVersion 25 "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } if (line.contains("applicationId") && !line.contains("//applicationId")) { String s = line.substring(line.indexOf("applicationId")).toString(); String str = line.replace(s, "//" + s + " "); buildGradleFile.seek(lastPoint); buildGradleFile.writeBytes(str); } lastPoint = ponit; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private boolean checkInput() { if ("".equals(sourcePath_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入源工程文件路径"); return true; } if ("".equals(output_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入apk输出路径"); return true; } if ("".equals(sdk_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入本地sdk路径"); return true; } if ("".equals(ndk_text.getText().toString())) { JOptionPane.showMessageDialog(jFrame, "请输入本地ndk路径"); return true; } return false; } public static String timeStamp2Date(String time) { Long timeLong = Long.parseLong(time); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");//要转换的时间格式 Date date; try { date = sdf.parse(sdf.format(timeLong)); return sdf.format(date); } catch (ParseException e) { e.printStackTrace(); return null; } } }
效果图
以上是关于关于打Android aar离线包的一些经验分享的主要内容,如果未能解决你的问题,请参考以下文章