使用什么方法来保护这个 Android APK:反射?加密?我如何对其进行逆向工程并分析?

2023-12-06

我了解 java 编程的基础知识,但我对逆向工程 APK 很陌生,所以解释会很好!


我有一个 APK 文件,但没有 Java 源代码。在线反编译APK后:

大部分应用程序隐藏在

资产 >classes.dex.dat

我发现的唯一的java文件是

com > ... > util > ProtectedUtils.java

我有下面的 ProtectedUtils.java :如果有人感兴趣,请链接到完整文件

   import android.app.Application;
    import android.app.Instrumentation;
    import android.content.Context;
    import android.os.Build.VERSION;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.List;

    public class ProtectedApplicationUtils extends Application {
        private static Application f0d;
        private static boolean f1d;
        private static transient Object[] f2d;
        private static Application dd;
        private static boolean gfgf;

        public ProtectedApplicationUtils() {
            dd = this;
        }

        private static final int attachBaseContext(int i, int i2) {
            int i3 = (i2 + i) >> 24;
            return (i >>> i2) | (i << (-i2));
        }

        public static Context attachBaseContext(Context context) {
            attachBaseContext();
            return context == dd ? f0d : context;
        }

        private static void attachBaseContext() {
            if (!f1d) {
                f1d = true;
                Class cls = Class.forName(m1d("\u50b3\uc849\ue145\ud010\udf4f\u45e5\u6b13\u36e0\u0e7b\ucae7\u774e\uc2b0\ub84a\udeeb\u9071\u3fd2\u3dd6\u3676\u95ca\u031b\udc13\ufaca\u3bf1\u0935\u75af\ud3d6"));
                Class[] clsArr = new Class[0];
                Object invoke = cls.getMethod(m1d("\u50b1\uc852\ue153\ud010\udf45\u45e2\u6b03\u368f\u0e79\ucae3\u7757\uc2e8\ub862\udefc\u907c\u3fef\u3dc8\u366d\u95db\u0303\udc23"), clsArr).invoke(null, new Object[0]);
                Field declaredField = cls.getDeclaredField(m1d("\u50bf\uc866\ue14d\ud00e\udf61\u45fc\u6b07\u36a2\u0e73\ucaf4\u775f\uc2ea\ub862\udee7\u906b\u3fc8"));
                declaredField.setAccessible(true);
                ((List) declaredField.get(invoke)).add(0, f0d);
                Field declaredField2 = cls.getDeclaredField(m1d("\u50bf\uc86e\ue14f\ud00b\udf54\u45e5\u6b16\u36a2\u0e5b\ucae7\u774e\uc2f2\ub862\udeeb\u9064\u3fcf\u3dc9\u3670\u95d0"));
                declaredField2.setAccessible(true);
                declaredField2.set(invoke, f0d);
                Field declaredField3 = cls.getDeclaredField(m1d("\u50bf\uc865\ue14e\ud017\udf4e\u45e8\u6b36\u36be\u0e6a\ucafb\u7757\uc2fd\ub86a\udefc\u906c\u3fd4\u3dce"));
                declaredField3.setAccessible(true);
                Object obj = declaredField3.get(invoke);
                Field declaredField4 = obj.getClass().getDeclaredField(m1d("\u50bb\uc849\ue147\ud00d"));
                declaredField4.setAccessible(true);
                Object obj2 = declaredField4.get(obj);
                Field declaredField5 = obj2.getClass().getDeclaredField(m1d("\u50bf\uc866\ue151\ud012\udf4c\u45e5\u6b14\u36af\u0e6e\ucafe\u7751\uc2f0"));
                declaredField5.setAccessible(true);
                declaredField5.set(obj2, f0d);
                Context baseContext = f0d.getBaseContext();
                Field declaredField6 = baseContext.getClass().getDeclaredField(m1d("\u50bf\uc868\ue154\ud016\udf45\u45fe\u6b34\u36a1\u0e74\ucae3\u775b\uc2e6\ub87f"));
                declaredField6.setAccessible(true);
                declaredField6.set(baseContext, f0d);
            }
        }

        private static final int m0d(byte[] bArr, int i) {
            Object obj = null;
            int i2 = bArr[14] << 16;
            Object obj2 = null;
            while (obj2 == null) {
                obj2 = 3;
                try {
                    return (bArr[(i >> 24) & 255] << 24) | (((bArr[i & 255] & 255) | ((bArr[(i >> 8) & 255] & 255) << 8)) | ((bArr[(i >> 16) & 255] & 255) << 16));
                } catch (Exception e) {
                }
            }
            while (obj == null) {
                obj = 2;
                try {
                    return bArr[i & 127] >> 8;
                } catch (Exception e2) {
                }
            }
            return i2;
        }

static final String m1d(String str) {
        if (f2d == null) {
            mark();
        }
        Object[] objArr = (Object[]) ((Method) f2d[8]).invoke(((Method) f2d[7]).invoke(null, null), null);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(((Method) f2d[10]).invoke(objArr[((Integer) f2d[12]).intValue()], null));
        int hashCode = stringBuilder.append(((Method) f2d[11]).invoke(objArr[((Integer) f2d[12]).intValue()], null)).toString().hashCode();
        int[] iArr = (int[]) f2d[6];
        int i = hashCode ^ iArr[0];
        int i2 = hashCode ^ iArr[1];
        int i3 = hashCode ^ iArr[2];
        int i4 = hashCode ^ iArr[3];
        iArr = (int[]) f2d[5];
        int[] iArr2 = (int[]) f2d[1];
        int[] iArr3 = (int[]) f2d[2];
        int[] iArr4 = (int[]) f2d[3];
        int[] iArr5 = (int[]) f2d[4];
        byte[] bArr = (byte[]) f2d[0];
        char[] cArr = (char[]) ((Method) f2d[9]).invoke(str, null);
        int i5 = i3;
        i3 = i2;
        i2 = i;
        i = i4;
        Object obj = null;
        while (obj == null) {
            try {
                int length = cArr.length;
                for (int i6 = 0; i6 < length; i6++) {
                    if (i6 % 8 == 0) {
                        int i7;
                        int i8;
                        int i9;
                        int i10 = i2 ^ iArr[0];
                        int i11 = i3 ^ iArr[1];
                        int i12 = i5 ^ iArr[2];
                        i4 = iArr[3] ^ i;
                        int i13 = 4;
                        while (i13 < 36) {
                            i7 = (((iArr2[i10 & 255] ^ iArr3[(i11 >> 8) & 255]) ^ iArr4[(i12 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                            i8 = (((iArr2[i11 & 255] ^ iArr3[(i12 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i10 >>> 24]) ^ iArr[i13 + 1];
                            i9 = (((iArr2[i12 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i10 >> 16) & 255]) ^ iArr5[i11 >>> 24]) ^ iArr[i13 + 2];
                            i4 = (((iArr2[i4 & 255] ^ iArr3[(i10 >> 8) & 255]) ^ iArr4[(i11 >> 16) & 255]) ^ iArr5[i12 >>> 24]) ^ iArr[i13 + 3];
                            i13 += 4;
                            i10 = (((iArr2[i7 & 255] ^ iArr3[(i8 >> 8) & 255]) ^ iArr4[(i9 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                            i11 = iArr[i13 + 1] ^ (((iArr2[i8 & 255] ^ iArr3[(i9 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i7 >>> 24]);
                            i12 = (((iArr2[i9 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i7 >> 16) & 255]) ^ iArr5[i8 >>> 24]) ^ iArr[i13 + 2];
                            i4 = (((iArr2[i4 & 255] ^ iArr3[(i7 >> 8) & 255]) ^ iArr4[(i8 >> 16) & 255]) ^ iArr5[i9 >>> 24]) ^ iArr[i13 + 3];
                            i13 += 4;
                        }
                        i7 = (((iArr2[i10 & 255] ^ iArr3[(i11 >> 8) & 255]) ^ iArr4[(i12 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                        i8 = (((iArr2[i11 & 255] ^ iArr3[(i12 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i10 >>> 24]) ^ iArr[i13 + 1];
                        i9 = (((iArr2[i12 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i10 >> 16) & 255]) ^ iArr5[i11 >>> 24]) ^ iArr[i13 + 2];
                        i4 = (((iArr2[i4 & 255] ^ iArr3[(i10 >> 8) & 255]) ^ iArr4[(i11 >> 16) & 255]) ^ iArr5[i12 >>> 24]) ^ iArr[i13 + 3];
                        i12 = i13 + 4;
                        i2 = iArr[i12 + 0] ^ ((((bArr[i7 & 255] & 255) ^ ((bArr[(i8 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i9 >> 16) & 255] & 255) << 16)) ^ (bArr[i4 >>> 24] << 24));
                        i3 = iArr[i12 + 1] ^ ((((bArr[i8 & 255] & 255) ^ ((bArr[(i9 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i4 >> 16) & 255] & 255) << 16)) ^ (bArr[i7 >>> 24] << 24));
                        i5 = iArr[i12 + 2] ^ ((((bArr[i9 & 255] & 255) ^ ((bArr[(i4 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i7 >> 16) & 255] & 255) << 16)) ^ (bArr[i8 >>> 24] << 24));
                        i = iArr[i12 + 3] ^ ((((bArr[i4 & 255] & 255) ^ ((bArr[(i7 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i8 >> 16) & 255] & 255) << 16)) ^ (bArr[i9 >>> 24] << 24));
                    }
                    obj = null;
                    while (obj == null) {
                        obj = 3;
                        try {
                            switch (i6 % 8) {
                                case 0:
                                    cArr[i6] = (char) ((i2 >> 16) ^ cArr[i6]);
                                    break;
                                case 1:
                                    cArr[i6] = (char) (cArr[i6] ^ i2);
                                    break;
                                case 2:
                                    cArr[i6] = (char) ((i3 >> 16) ^ cArr[i6]);
                                    break;
                                case 3:
                                    cArr[i6] = (char) (cArr[i6] ^ i3);
                                    break;
                                case 4:
                                    cArr[i6] = (char) ((i5 >> 16) ^ cArr[i6]);
                                    break;
                                case 5:
                                    cArr[i6] = (char) (cArr[i6] ^ i5);
                                    break;
                                case 6:
                                    cArr[i6] = (char) ((i >> 16) ^ cArr[i6]);
                                    break;
                                case 7:
                                    cArr[i6] = (char) (cArr[i6] ^ i);
                                    break;
                                default:
                                    break;
                            }
                        } catch (Throwable th) {
                        }
                    }
                }
                return new String(cArr);
            } catch (Throwable th2) {
                i4 = 1;
            }
        }
        return new String(cArr);
    }


     private void eee() {
            if (!gfgf) {


    ...


     byte[] bArr = new byte[length];
                int i = 0;
                for (int i2 = 1; i2 < toCharArray.length; i2++) {
                    char c = toCharArray[i2];
                    int i3 = i + 1;
                    bArr[i] = (byte) (c >> 8);
                    i = i3 + 1;
                    bArr[i3] = (byte) c;
                }
                length -= toCharArray[0];
                Class cls = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue12c\u66ac\uc08c\u48ca\u17b8\ua701"));
                Class cls2 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac94\u5137\ubcfd\u7954\uc61d\ue113\u66bd"));
                Constructor constructor = cls2.getConstructor(new Class[]{cls2, cls});
                Method method = Class.forName(m1d("\u6af7\u53e5\ue9f5\u77c2\ueebf\uac94\u513c\ubcfd\u7971\uc61b\ue111\u66ac\uc09b\u48cd\u17a2\ua748\u6dfc\u8c7c\ud17e\u8ccc\u9348\ue1fb\u6b56")).getMethod(m1d("\u6af1\u53ee\ue9e5\u77f4\ueeb9\uac8f"), new Class[]{cls, Integer.TYPE});
                Object invoke = method.invoke(this, new Object[]{m1d("\u6af2\u53ee\ue9e9"), Integer.valueOf(0)});
                Object invoke2 = method.invoke(this, new Object[]{m1d("\u6af9\u53fe\ue9e5\u77d4\ueeb5\uac85"), Integer.valueOf(0)});
                Object newInstance = constructor.newInstance(new Object[]{invoke, m1d("\u6af8\u53ee\ue9e6\u779e\ueeb1\uac8d\u5133")});
                Object newInstance2 = constructor.newInstance(new Object[]{invoke2, m1d("\u6af8\u53ee\ue9e6\u779e\ueebf\uac99\u513d\ubcab")});
                Class cls3 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac94\u5137\ubcfd\u7954\uc61d\ue113\u66bd\uc0b1\u48d6\u17a2\ua716\u6dca\u8c67\ud143\u8ccc\u935f\ue1e6\u6b43\u5edf"));
                Object newInstance3 = cls3.getConstructor(new Class[]{cls2}).newInstance(new Object[]{newInstance});
                try {
                    cls3.getMethod(m1d("\u6ae1\u53f9\ue9f8\u77c4\ueeb5"), new Class[]{byte[].class, Integer.TYPE, Integer.TYPE}).invoke(newInstance3, new Object[]{bArr, Integer.valueOf(0), Integer.valueOf(length)});
                    Class[] clsArr = new Class[0];
                    cls3.getMethod(m1d("\u6af5\u53e7\ue9fe\u77c3\ueeb5"), clsArr).invoke(newInstance3, new Object[0]);
                    clsArr = new Class[0];
                    Method method2 = cls2.getMethod(m1d("\u6af1\u53ee\ue9e5\u77f3\ueeb1\uac93\u5137\ubcbd\u797b\uc617\ue11e\u66b4\uc0ae\u48c2\u17a2\ua70e"), clsArr);
                    Class cls4 = Class.forName(m1d("\u6af2\u53ea\ue9fd\u77c6\ueeb9\uac96\u5176\ubca0\u796b\uc607\ue10b\u66bd\uc093\u488d\u1792\ua703\u6dc7\u8c55\ud179\u8cd4\u9348"));
                    Method method3 = cls4.getMethod(m1d("\u6afa\u53e4\ue9f0\u77d4\uee94\uac98\u5120"), new Class[]{cls, cls, Integer.TYPE});
                    Object[] objArr = new Object[3];
                    objArr[0] = method2.invoke(newInstance, new Object[0]);
                    objArr[1] = method2.invoke(newInstance2, new Object[0]);
                    objArr[2] = Integer.valueOf(0);
                    Object invoke3 = method3.invoke(null, objArr);
                    clsArr = new Class[0];
                    Method method4 = cls2.getMethod(m1d("\u6af2\u53ee\ue9fd\u77d5\ueea4\uac98"), clsArr);
                    method4.invoke(newInstance, new Object[0]);
                    method4.invoke(newInstance2, new Object[0]);
                    Method method5 = cls4.getMethod(m1d("\u6afa\u53e4\ue9f0\u77d4\uee93\uac91\u5139\ubca0\u7961"), new Class[]{cls, Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue13c\u66b4\uc09f\u48d0\u17a5\ua72a\u6dd0\u8c72\ud174\u8cdd\u935f"))});
                    Class cls5 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue130\u66ba\uc094\u48c6\u17b5\ua712"));
                    ((Class) method5.invoke(invoke3, new Object[]{m1d("\u6af5\u53e4\ue9fc\u779e\ueeba\uac88\u512c\ubcb6\u7960\uc615\ue113\u66b9\uc09c\u48d0\u17f8\ua716\u6dda\u8c61\ud17b\u8ccc\u935b\ue1ad\u6b57\u5ec6\uac55\u9c90\u04b4\u6b93\u02ab\uabec\u14eb\u3f1e\u589d\ue4b6\ubf55\u7b7b\u67f0\ud0e1\u70f9\u6f15\u22d4\u6219\u6c03\u20df\ua4e9\ub5ca\ue4d1\uee2a\ubce9\ua0fc\u5d07\u1579\u6e23\uf7c8\u849d\u10a5\ucf27\u8cbd\ue95c\u3482\udec5\ua61d\u5956\u6e32\u7e60\ua68a\u87d6"), getClass().getClassLoader()})).getDeclaredMethod(m1d("\u6af3\u53ee\ue9f7\u77d4"), new Class[]{cls5, cls5}).invoke(this, new Object[]{this, invoke3});
                    gfgf = true;
                } catch (Throwable th) {
                    Class[] clsArr2 = new Class[0];
                    cls3.getMethod(m1d("\u6af5\u53e7\ue9fe\u77c3\ueeb5"), clsArr2).invoke(newInstance3, new Object[0]);
                }
            }
        }

 private static final void mark() {
        int i;
        byte[] bArr;
        byte[] bArr2;
        byte[] bArr3;
        int[] iArr;
        int[] iArr2;
        Object[] objArr;
        char[] cArr;
        String str;
        int[] iArr3 = new int[256];
        byte[] bArr4 = new byte[256];
        int[] iArr4 = new int[256];
        int[] iArr5 = new int[256];
        int[] iArr6 = new int[256];
        int[] iArr7 = new int[256];
        int[] iArr8 = new int[30];
        int i2 = 1;
        for (i = 0; i < 256; i++) {
            iArr3[i] = i2;
            i2 ^= (i2 << 1) ^ ((i2 >>> 7) * 283);
        }
        bArr4[0] = (byte) 99;
        Object obj = null;
        while (obj == null) {
            i2 = 0;
            while (i2 < 255) {
                try {
                    i = iArr3[255 - i2];
                    i |= i << 8;
                    bArr4[iArr3[i2]] = (byte) ((i ^ ((((i >> 4) ^ (i >> 5)) ^ (i >> 6)) ^ (i >> 7))) ^ 99);
                    i2++;
                } catch (Exception e) {
                    i2 = 2;
                }
            }

...


        for (i2 = 0; i2 < cArr.length; i2++) {
            cArr[i2] = (char) (cArr[i2] - bArr2[i2 % bArr2.length]);
        }
        objArr[7] = Class.forName(String.valueOf(cArr, 0, 16)).getMethod(String.valueOf(cArr, 16, 13), null);
        objArr[8] = Class.forName(String.valueOf(cArr, 0, 16)).getMethod(String.valueOf(cArr, 29, 13), null);
        objArr[9] = Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 58, 11), null);
        objArr[10] = Class.forName(String.valueOf(cArr, 69, 27)).getMethod(String.valueOf(cArr, 96, 12), null);
        objArr[11] = Class.forName(String.valueOf(cArr, 69, 27)).getMethod(String.valueOf(cArr, 108, 13), null);
        str = (String) Class.forName(String.valueOf(cArr, 121, 27)).getMethod(String.valueOf(cArr, 148, 3), new Class[]{Class.forName(String.valueOf(cArr, 42, 16))}).invoke(null, new Object[]{String.valueOf(cArr, 151, 25)});
        if (str != null) {
            i2 = str.hashCode();
            i2 = 4;
            objArr[12] = Integer.valueOf(i2);
            f2d = objArr;
            i2 = ((Integer) Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 214, 8), new Class[0]).invoke(Class.forName(String.valueOf(cArr, 176, 16)).getField(String.valueOf(cArr, 192, 6)).get(null), new Object[0])).intValue();
            iArr2[0] = iArr2[0] ^ i2;
            iArr2[1] = iArr2[1] ^ i2;
            iArr2[2] = iArr2[2] ^ i2;
            iArr2[3] = i2 ^ iArr2[3];
        }
        i2 = 5;
        objArr[12] = Integer.valueOf(i2);
        f2d = objArr;
        i2 = ((Integer) Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 214, 8), new Class[0]).invoke(Class.forName(String.valueOf(cArr, 176, 16)).getField(String.valueOf(cArr, 192, 6)).get(null), new Object[0])).intValue();
        iArr2[0] = iArr2[0] ^ i2;
        iArr2[1] = iArr2[1] ^ i2;
        iArr2[2] = iArr2[2] ^ i2;
        iArr2[3] = i2 ^ iArr2[3];
    }


    protected void m2attachBaseContext(Context context) {
        super.attachBaseContext(context);
        eee();
        f0d = Instrumentation.newApplication(Class.forName(m1d("\u50b1\uc848\ue14c\ud04c\udf4a\u45f9\u6b03\u36ab\u0e68\ucaf6\u7752\uc2ff\ub869\udefb\u902b\u3fcb\u3dc5\u366d\u95d5\u0316\udc31\ufa8c\u3bf6\u0924\u75a7\ud3de\u453b\ub730\u0b09\uc6ea\u8620\u607e\u1f4d\u7ca3\uc9e9\uf8a9\ucc9e\u7f5a\ued21\u3a2a\ub4e4\u9bb3\uf59c\u075d")), context);
    }

    public void onCreate() {
        super.onCreate();
        attachBaseContext();
        f0d.onCreate();
    }
}

我认为它使用了某种加密以及 Java.Reflection API。如果您能解释一下这个文件的用途,那就太好了。

如果我想分析应用程序的工作原理,然后修改其行为、重新编译并运行它,那么最好的开始方式是什么?

我是否尝试重建解密方法并尝试解密所有字符串和dex?

有没有什么好的工具可以使用?

(如果您需要查看文件的其余部分,请告诉我)


另请注意:由于 APK 中设置的限制,我无法在我的设备上运行该应用程序。它会说“应用程序在我尝试打开它后立即停止了。”


Edit:

我一直在尝试测试各个方法:

我粘贴了mark()以及它所依赖的方法/变量(例如m0d(), attachBaseContext(), f2d, and apkversion)在一个新的java类中。

当我尝试运行时,它卡在“正在运行”状态,进度条冻结在 0。


代码来自DexGuard- 高级商业版本ProGuard。它的工作原理不同。

尝试阅读此处的答案:Stackoverflow:DexGuard 如何加密类?

我认为我不应该在这里复制它,但答案的总结是你必须非常熟悉Java、Reflection以及Dalvik和ART的工作方式,这样你就可以手动解密这些类。即使对于专业人士来说,这也足够困难了。

无论如何,即使你这样做,你仍然看不到代码的原始结构,因为所有变量都失去了原始名称,方法被重命名为毫无意义的东西,原始类可以(而且我认为它们会)被划分为多个更小的类。

如果你真的想开始这个过程,我认为,你应该找到一些用 ProGuard 混淆的 APK 并尝试理解它的作用。在了解它的工作原理并且能够足够好地阅读混淆的代码后,尝试使用从应用程序中获得的方法创建一个应用程序,看看它到底做了什么。我认为在某些时候您将获得解密 .dat 文件的类和方法,并且能够看到它们的内容。祝你好运。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用什么方法来保护这个 Android APK:反射?加密?我如何对其进行逆向工程并分析? 的相关文章

  • 如何在 Android / Java 中获取图像的分辨率

    如何在 Android 中找到任何图像的分辨率 获取存储在磁盘中的图像大小的有效方法 例如获取用户选择上传的图像文件的大小 是使用BitmapFactory Options并设置inJustDecodeBounds为真 这样做你就会获取图像
  • TypedArray 的 getResourceId 方法

    我正在阅读有关的文档获取资源Id https developer android com reference android content res TypedArray html getResourceId int 20int 方法 它说
  • 使用库来维护免费/付费的应用程序版本

    维护免费 付费应用程序版本的共识似乎是使用库 并从每个活动中设置一个标志 以从代码库中获取不同的功能 这有多安全 据我了解 一个人可以root他们的手机 获取APK 并且可以对其进行反编译 即使代码被混淆 也不难看出该应用程序是带有标志的包
  • android webview 函数 onPagefinished 被调用两次

    我的android webview功能onPageFinished被调用两次 我不知道为什么 但它在 android 2 2 上运行良好 但当我将其升级到 4 时 它就不起作用了 代码附在下面 Code Override public vo
  • Android 自定义视图不能以正确的方式处理透明度/alpha

    我正在绘制自定义视图 在此视图中 我使用两个不同的绘画和路径对象在画布上绘画 我基本上是在绘制两个重叠的形状 添加 Alpha 后 视图中重叠的部分比图像的其余部分更暗 这是不希望的 但我不知道如何解决它 这是我的代码片段 用于展示我如何在
  • 如何获取.so文件的依赖项列表?

    假设我有libFoo so为 android arm 编译 我不确定它链接到什么STL实现 有options http developer android com intl ru ndk guides standalone toolchai
  • 在 Android 中长按时从操作模式中删除后退/主页按钮

    我已经在里面长按实现了上下文操作模式recycler view 为此我打电话给ActionModeCallback从创建动作模式开始 创建动作模式时 默认显示后退箭头 检查如下 单击后退箭头 操作模式将关闭 现在我想要hide or rem
  • FileNotFoundException:/存储/模拟/0/Android

    我尝试这个文件写入器 读取器代码段进行测试 File file new File Environment getExternalStorageDirectory LM lm lisdat 01 txt FileOutputStream ou
  • Retrofit-2 内容类型问题

    我的 Api 接受 Content Type application json 作为标头 我按照改造文档中所述完美设置了标题 Headers Content Type application json POST user classes C
  • 如何从 Retrofit2 获取字符串响应?

    我正在做 android 正在寻找一种方法来执行超级基本的 http GET POST 请求 我不断收到错误 java lang IllegalArgumentException Unable to create converter for
  • 应用内结算错误

    我的 UNMANAGED 应用内购买无法正常工作 在它完美运行之前 我可以使用测试帐户成功购买 但它突然不起作用了 因为我记得我对商家帐户所做的只是添加更多 2 4 个测试帐户 添加后 我的应用内购买将不起作用 所以我更新了公钥并上传了一个
  • 如何防止布局的方向改变,而不是整个屏幕/活动的方向改变

    我需要一个子布局 可以是任何布局 例如FrameLayout or RelativeLayout 忽略方向变化并始终保持横向 但不是它的父级或任何其他兄弟布局 视图 它们应该相应地改变它们的方向 因此 我不能使用setRequestedOr
  • 使用 CryptoJS 更改密钥 [重复]

    这个问题在这里已经有答案了 我正在使用 CryptoJS 来加密和解密文本 在这里 我只是获取消息并显示加密和解密消息 我使用DES算法进行加密和解密 这是我的 HTML 文件
  • 在 Jetpack Compose 中跨可组合函数重复使用一组预览注释

    在 Jetpack Compose 中迈出第一步 这非常令人惊奇 除了一个恼人的问题 我有一组固定的预览 正常 深色和 RTL Preview name Normal group Screen showBackground true Pre
  • 如何在 Android NDK 中创建新的 NativeWindow 而无需 Android 操作系统源代码?

    我想编译一个 Android OpenGL 控制台应用程序 您可以直接从控制台启动 Android x86 运行 或者从 Android x86 GUI 内的 Android 终端应用程序运行 这个帖子 如何在 Android NDK 中创
  • 如何以编程方式启动 ssh 服务器 android,以及如何获取连接到设备的用户名和密码

    我正在开发像这样的应用程序sshdroid 我想在 Android 操作系统上打开 ssh 连接 并且我想从电脑连接应用程序 我使用了 JSCH lib 但是这个lib用于将android连接到pc 我的要求是pc到android 任何人都
  • Android - 如何更改 TimePicker 中的文本颜色?

    我正在使用 TimePicker 到 LinearLayout 中 背景颜色 黑色 但是 我看不到 TimePicker 中的数字 并且我需要在布局中将背景颜色设置为黑色 如何更改 TimePicker 中的 textColor 我已经尝试
  • android httprequest java.net.UnknownHostException

    我想用android发出http请求 是使用这个 void testHTTP HttpClient httpClient new DefaultHttpClient HttpUriRequest request new HttpPost h
  • 安卓的限制

    我需要构建一个应用程序 该应用程序拍摄相机图像并将其上传到网络 在网络上进行一些处理并返回真 假 我在这方面遇到了一些问题 希望得到澄清 1 我的应用程序有什么方法可以知道 Android 相机捕获的图像吗 我从这里明白了什么 Androi
  • 在 Android 中使用 iText 将图像添加到特定位置

    我想使用 Android 中的 iText 将图像添加到 PDF 文件中的特定位置 这是一个可填写的表单 我添加了作为图像占位符的文本框 我想要做的就是像这样获取该文本框和图像 public class FormFill public st

随机推荐