-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
80 changed files
with
604 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.mainli.apk; | ||
|
||
import com.android.apksig.ApkSigner; | ||
import com.android.build.gradle.api.ApkVariant; | ||
import com.android.builder.model.SigningConfig; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.security.KeyStore; | ||
import java.security.KeyStoreException; | ||
import java.security.PrivateKey; | ||
import java.security.cert.Certificate; | ||
import java.security.cert.X509Certificate; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class ApkSign { | ||
public static File sign(File inputApk, ApkVariant variant) { | ||
return sign(inputApk, variant.getSigningConfig(), variant.getPackageApplicationProvider().get().getMinSdkVersion().get()); | ||
} | ||
|
||
public static File sign(File inputApk, SigningConfig signingConfig, int minSdkVersion) { | ||
File keystoreFile = signingConfig.getStoreFile(); | ||
String keystorePassworld = signingConfig.getStorePassword(); | ||
String keystoreAlias = signingConfig.getKeyAlias(); | ||
String keystoreAliasPassworld = signingConfig.getKeyPassword(); | ||
File outputApk = new File(inputApk.getParentFile(), "_single.apk"); | ||
String defaultType = KeyStore.getDefaultType();//jks | ||
try { | ||
KeyStore ks = KeyStore.getInstance(defaultType); | ||
loadKeyStoreFromFile(ks, keystoreFile, keystorePassworld); | ||
if (ks.isKeyEntry(keystoreAlias)) { | ||
Certificate[] certChain = ks.getCertificateChain(keystoreAlias); | ||
|
||
PrivateKey privateKey = (PrivateKey) ks.getKey(keystoreAlias, keystoreAliasPassworld.toCharArray()); | ||
List<X509Certificate> certs = new ArrayList<>(certChain.length); | ||
for (Certificate cert : certChain) { | ||
certs.add((X509Certificate) cert); | ||
} | ||
String v1SigBasename = null; | ||
String keyFileName = keystoreFile.getName(); | ||
int delimiterIndex = keyFileName.indexOf('.'); | ||
if (delimiterIndex == -1) { | ||
v1SigBasename = keyFileName; | ||
} else { | ||
v1SigBasename = keyFileName.substring(0, delimiterIndex); | ||
} | ||
ApkSigner.SignerConfig signerConfig = new ApkSigner.SignerConfig.Builder(v1SigBasename, privateKey, certs).build(); | ||
|
||
|
||
ApkSigner.Builder apkSignerBuilder = new ApkSigner.Builder(Arrays.asList(signerConfig)).setInputApk(inputApk).setOutputApk(outputApk).setOtherSignersSignaturesPreserved(false).setV1SigningEnabled(signingConfig.isV1SigningEnabled())// | ||
.setV2SigningEnabled(signingConfig.isV2SigningEnabled())// | ||
.setV3SigningEnabled(signingConfig.isV2SigningEnabled()); | ||
apkSignerBuilder.setMinSdkVersion(minSdkVersion); | ||
ApkSigner apkSigner = apkSignerBuilder.build(); | ||
try { | ||
apkSigner.sign(); | ||
return outputApk; | ||
} catch (Exception e) { | ||
} | ||
} | ||
} catch (KeyStoreException e) { | ||
e.printStackTrace(); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
private static void loadKeyStoreFromFile(KeyStore ks, File file, String passwordStr) throws Exception { | ||
List<char[]> passwords = Arrays.asList(passwordStr.toCharArray()); | ||
Exception lastFailure = null; | ||
for (char[] password : passwords) { | ||
try { | ||
try (FileInputStream in = new FileInputStream(file)) { | ||
ks.load(in, password); | ||
} | ||
return; | ||
} catch (Exception e) { | ||
lastFailure = e; | ||
} | ||
} | ||
if (lastFailure == null) { | ||
throw new RuntimeException("No keystore passwords"); | ||
} else { | ||
throw lastFailure; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package com.mainli.apk; | ||
|
||
import com.android.utils.FileUtils; | ||
|
||
import java.io.Closeable; | ||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.util.Enumeration; | ||
import java.util.zip.ZipEntry; | ||
import java.util.zip.ZipFile; | ||
import java.util.zip.ZipOutputStream; | ||
|
||
public class ZipUtil { | ||
private static final int BUFFERSIZE = 1024; | ||
|
||
public static File appendFile(File apk, String prefix, File file) { | ||
if (apk == null || !apk.exists() || file == null || !file.exists()) { | ||
return null; | ||
} | ||
File outPutApk = new File(apk.getParentFile(), "_appendFileUnsigned.apk"); | ||
ZipFile inputZip = null; | ||
FileOutputStream fileOutputStream = null; | ||
ZipOutputStream zipOutputStream = null; | ||
try { | ||
inputZip = new ZipFile(apk); | ||
Enumeration<? extends ZipEntry> entries = inputZip.entries(); | ||
//创建压缩包 | ||
fileOutputStream = new FileOutputStream(outPutApk); | ||
zipOutputStream = new ZipOutputStream(fileOutputStream); | ||
while (entries.hasMoreElements()) { | ||
addZipFile2ZipOutputStream(inputZip, entries.nextElement(), zipOutputStream); | ||
} | ||
StringBuilder builder = new StringBuilder(prefix); | ||
if (builder.charAt(builder.length() - 1) == '/') { | ||
builder.deleteCharAt(builder.length() - 1); | ||
} | ||
builder.append('/').append(file.getName()); | ||
if (file.isDirectory()) { | ||
builder.append('/'); | ||
} | ||
addFile2ZipOutputStream(file, builder.toString(), zipOutputStream); | ||
zipOutputStream.flush(); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
outPutApk = null; | ||
} finally { | ||
close(inputZip); | ||
close(zipOutputStream); | ||
} | ||
return outPutApk; | ||
} | ||
|
||
public static void addZipFile2ZipOutputStream(ZipFile inputZip, ZipEntry sourceZipEntry, ZipOutputStream zipOutputStream) { | ||
InputStream is = null; | ||
try { | ||
is = inputZip.getInputStream(sourceZipEntry); | ||
int len = 0; | ||
zipOutputStream.putNextEntry(new ZipEntry(sourceZipEntry.getName())); | ||
byte[] bufer = new byte[BUFFERSIZE]; | ||
while ((len = is.read(bufer)) > 0) { | ||
zipOutputStream.write(bufer, 0, len); | ||
} | ||
zipOutputStream.flush(); | ||
zipOutputStream.closeEntry(); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
close(is); | ||
} | ||
} | ||
|
||
public static void close(Closeable closeable) { | ||
if (closeable != null) { | ||
try { | ||
closeable.close(); | ||
} catch (IOException e) { | ||
} | ||
} | ||
} | ||
|
||
public static void addFile2ZipOutputStream(File file, String relativePath, ZipOutputStream zos) { | ||
InputStream is = null; | ||
try { | ||
if (!file.isDirectory()) { | ||
ZipEntry zp = new ZipEntry(relativePath); | ||
zos.putNextEntry(zp); | ||
is = new FileInputStream(file); | ||
byte[] buffer = new byte[BUFFERSIZE]; | ||
int length = 0; | ||
while ((length = is.read(buffer)) >= 0) { | ||
zos.write(buffer, 0, length); | ||
} | ||
zos.flush(); | ||
zos.closeEntry(); | ||
} else { | ||
String tempPath = null; | ||
for (File f : file.listFiles()) { | ||
tempPath = relativePath + f.getName(); | ||
if (f.isDirectory()) { | ||
tempPath += "/"; | ||
} | ||
addFile2ZipOutputStream(f, tempPath, zos); | ||
} | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
close(is); | ||
} | ||
} | ||
|
||
public static File unZipFile(ZipFile inputZip, ZipEntry sourceZipEntry, File dir) { | ||
if (inputZip == null || sourceZipEntry == null || dir == null) { | ||
return null; | ||
} | ||
InputStream inputStream = null; | ||
FileOutputStream outputStream = null; | ||
try { | ||
inputStream = inputZip.getInputStream(sourceZipEntry); | ||
int len = 0; | ||
File file = new File(dir, sourceZipEntry.getName()); | ||
File parentFile = file.getParentFile(); | ||
if (!parentFile.exists()) { | ||
parentFile.mkdirs(); | ||
} | ||
outputStream = new FileOutputStream(file); | ||
byte[] bufer = new byte[BUFFERSIZE]; | ||
while ((len = inputStream.read(bufer)) > 0) { | ||
outputStream.write(bufer, 0, len); | ||
} | ||
outputStream.flush(); | ||
return file; | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
close(outputStream); | ||
close(inputStream); | ||
} | ||
return null; | ||
} | ||
} |
Oops, something went wrong.