Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iOS, Android): add AppUUID Lib for plugins #5690

Merged
merged 3 commits into from Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 65 additions & 0 deletions android/capacitor/src/main/java/com/getcapacitor/AppUUID.java
@@ -0,0 +1,65 @@
package com.getcapacitor;

import android.content.Context;
import android.content.SharedPreferences;
import androidx.appcompat.app.AppCompatActivity;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
import java.util.UUID;

public final class AppUUID {

private static final String KEY = "CapacitorAppUUID";

public static String getAppUUID(AppCompatActivity activity) throws Exception {
assertAppUUID(activity);
return readUUID(activity);
}

public static void regenerateAppUUID(AppCompatActivity activity) throws Exception {
try {
String uuid = generateUUID();
writeUUID(activity, uuid);
} catch (NoSuchAlgorithmException ex) {
throw new Exception("Capacitor App UUID could not be generated.");
}
}

private static void assertAppUUID(AppCompatActivity activity) throws Exception {
String uuid = readUUID(activity);
if (uuid.equals("")) {
regenerateAppUUID(activity);
}
}

private static String generateUUID() throws NoSuchAlgorithmException {
MessageDigest salt = MessageDigest.getInstance("SHA-256");
salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
return bytesToHex(salt.digest());
}

private static String readUUID(AppCompatActivity activity) {
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
return sharedPref.getString(KEY, "");
}

private static void writeUUID(AppCompatActivity activity, String uuid) {
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(KEY, uuid);
editor.apply();
}

private static String bytesToHex(byte[] bytes) {
byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
}
4 changes: 4 additions & 0 deletions ios/Capacitor/Capacitor.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
0F83E885285A332E006C43CB /* AppUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F83E884285A332D006C43CB /* AppUUID.swift */; };
2F81F5C926FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F81F5C726FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h */; };
2F81F5CA26FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F81F5C826FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m */; };
373A69C1255C9360000A6F44 /* NotificationHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */; };
Expand Down Expand Up @@ -138,6 +139,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
0F83E884285A332D006C43CB /* AppUUID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUUID.swift; sourceTree = "<group>"; };
2F81F5C726FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CAPBridgeViewController+CDVScreenOrientationDelegate.h"; sourceTree = "<group>"; };
2F81F5C826FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CAPBridgeViewController+CDVScreenOrientationDelegate.m"; sourceTree = "<group>"; };
373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandlerProtocol.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -355,6 +357,7 @@
373A69F1255C95D0000A6F44 /* NotificationRouter.swift */,
62E79C562638AF7500414164 /* assets */,
A71289E527F380A500DADDF3 /* Router.swift */,
0F83E884285A332D006C43CB /* AppUUID.swift */,
);
path = Capacitor;
sourceTree = "<group>";
Expand Down Expand Up @@ -616,6 +619,7 @@
62FABD1A25AE5C01007B3814 /* Array+Capacitor.swift in Sources */,
62959B172524DA7800A3D7F1 /* JSExport.swift in Sources */,
373A69C1255C9360000A6F44 /* NotificationHandlerProtocol.swift in Sources */,
0F83E885285A332E006C43CB /* AppUUID.swift in Sources */,
625AF1ED258963C700869675 /* WebViewAssetHandler.swift in Sources */,
62959B3C2524DA7800A3D7F1 /* CAPBridgeDelegate.swift in Sources */,
62959B2F2524DA7800A3D7F1 /* DefaultPlugins.m in Sources */,
Expand Down
53 changes: 53 additions & 0 deletions ios/Capacitor/Capacitor/AppUUID.swift
@@ -0,0 +1,53 @@
import CommonCrypto
import Foundation

private func hexString(_ iterator: Array<UInt8>.Iterator) -> String {
return iterator.map { String(format: "%02x", $0) }.joined()
}

extension Data {
public var sha256: String {
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
self.withUnsafeBytes { bytes in
_ = CC_SHA256(bytes.baseAddress, CC_LONG(self.count), &digest)
}
return hexString(digest.makeIterator())
}
}

public class AppUUID {
private static let key: String = "CapacitorAppUUID"

public static func getAppUUID() -> String {
assertAppUUID()
return readUUID()
}

public static func regenerateAppUUID() {
let uuid = generateUUID()
writeUUID(uuid)
}

private static func assertAppUUID() {
let uuid = readUUID()
if uuid == "" {
regenerateAppUUID()
}
}

private static func generateUUID() -> String {
let uuid: String = UUID.init().uuidString
return uuid.data(using: .utf8)!.sha256
}

private static func readUUID() -> String {
let defaults = UserDefaults.standard
return defaults.string(forKey: key) ?? ""
}

private static func writeUUID(_ uuid: String) {
let defaults = UserDefaults.standard
defaults.set(uuid, forKey: key)
}

}