首页 文章 精选 留言 我的

精选列表

搜索[visual studio code],共10000篇文章
优秀的个人博客,低调大师

25.Android Studio下Ndk开发(参数加密解决方案)

网络请求通过http传递到后台,如果不对数据做加密处理的话,很容易会被抓包,此时,app就是很不安全的,被截取到接口地址和参数后容易被攻击。今天我要分享的就是如何提高网络接口安全性的解决方案。 之前做的项目是采取直接在java层对参数进行加密,加密方式也有很多,RSA加密,MD5加密,AES加密,DES加密,Base64加密等等,具体介绍可以参考这里 Android中的加密方法(http://www.cnblogs.com/whoislcj/p/5470095.html),这种方式在一定程度上可以提高数据的安全性,但是深入来看,我们的加密方式对外暴露出来,当app被反编译时,对方可以拿到我们的代码,可以看到我们加密的方式,这样一来,会更加容易让对方找到破解密文的方法,因为在目前所有加密方式中,既具备实用性又具备绝对安全性的方法是不存在的。所以我们是否可以做到加密方式也对外不可见呢,或者如果不能做到绝对不可见,是否可以大大的提高对方破解密文的难度。这就是今天要做的,通过jni将加密方法打包到so库中,防止被放编译,算是在这些加密算法的上面加一层壳,这里以md5加密为例。 so库破解的难度之大,远远超过破解混淆后的apk,所以jni是解决安全性隐患的一个切入点。 创建CMakeLists文件,配置相关的内容 #参数加密 cmake_minimum_required(VERSION 3.4.1) find_library( log-lib log ) add_library( encrypt SHARED src/main/cpp/encrypt.cpp src/main/cpp/md5.cpp) # 将预构建库与本地库相连 target_link_libraries( encrypt ${log-lib} ) EncryptUtils package com.app.rzm.utils; import android.content.Context; /** * ndk实现参数加密 */ public class EncryptUtils { static { System.loadLibrary("encrypt"); } public static String encrypt(Context context, String param){ checkSignature(context); return encryptNative(context,param); } /** * 对一个字符串进行加密 * @param context * @param param * @return */ private static native String encryptNative(Context context, String param); /** * 校验app签名 * @param context */ private static native void checkSignature(Context context); } 调用方式 public class TestParamsEncryptActivity extends AppCompatActivity { private TextView mText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_params_encrypt); mText = (TextView) findViewById(R.id.text); //拿到签名 try { PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); Signature[] signatures = packageInfo.signatures; LogUtils.d("signature:"+signatures[0].toCharsString()); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } //将网络请求中的http参数拼接成这样的字符串username=renzhenming&password=123456 //然后将这个参数字符串进行加密 String params = EncryptUtils.encrypt(this,"username=renzhenming&password=123456"); //作为参数给到服务器,服务器也生成同样的密文,然后将加密的字符串进行比较 mText.setText(params); } } 接下来是关键代码,在c++中实现md5加密, * 加密解密的过程: md5.h #ifndef MD5_H #define MD5_H typedef struct { unsigned int count[2]; unsigned int state[4]; unsigned char buffer[64]; }MD5_CTX; #define F(x,y,z) ((x & y) | (~x & z)) #define G(x,y,z) ((x & z) | (y & ~z)) #define H(x,y,z) (x^y^z) #define I(x,y,z) (y ^ (x | ~z)) #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) #define FF(a,b,c,d,x,s,ac) { \ a += F(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define GG(a,b,c,d,x,s,ac) { \ a += G(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define HH(a,b,c,d,x,s,ac) { \ a += H(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define II(a,b,c,d,x,s,ac) { \ a += I(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); void MD5Final(MD5_CTX *context, unsigned char digest[16]); void MD5Transform(unsigned int state[4], unsigned char block[64]); void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); #endif md5.cpp #include "md5.h" #include "string" unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //在逆向代码的时候,需要关注下面的特征值 void MD5Init(MD5_CTX *context) { context->count[0] = 0; context->count[1] = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; } void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) { unsigned int i = 0, index = 0, partlen = 0; index = (context->count[0] >> 3) & 0x3F; partlen = 64 - index; context->count[0] += inputlen << 3; if (context->count[0] < (inputlen << 3)) context->count[1]++; context->count[1] += inputlen >> 29; if (inputlen >= partlen) { memcpy(&context->buffer[index], input, partlen); MD5Transform(context->state, context->buffer); for (i = partlen; i + 64 <= inputlen; i += 64) MD5Transform(context->state, &input[i]); index = 0; } else { i = 0; } memcpy(&context->buffer[index], &input[i], inputlen - i); } void MD5Final(MD5_CTX *context, unsigned char digest[16]) { unsigned int index = 0, padlen = 0; unsigned char bits[8]; index = (context->count[0] >> 3) & 0x3F; padlen = (index < 56) ? (56 - index) : (120 - index); MD5Encode(bits, context->count, 8); MD5Update(context, PADDING, padlen); MD5Update(context, bits, 8); MD5Encode(digest, context->state, 16); } void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[j] = input[i] & 0xFF; output[j + 1] = (input[i] >> 8) & 0xFF; output[j + 2] = (input[i] >> 16) & 0xFF; output[j + 3] = (input[i] >> 24) & 0xFF; i++; j += 4; } } void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[i] = (input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24); i++; j += 4; } } void MD5Transform(unsigned int state[4], unsigned char block[64]) { unsigned int a = state[0]; unsigned int b = state[1]; unsigned int c = state[2]; unsigned int d = state[3]; unsigned int x[64]; MD5Decode(x, block, 64); FF(a, b, c, d, x[0], 7, 0xd76aa478); FF(d, a, b, c, x[1], 12, 0xe8c7b756); FF(c, d, a, b, x[2], 17, 0x242070db); FF(b, c, d, a, x[3], 22, 0xc1bdceee); FF(a, b, c, d, x[4], 7, 0xf57c0faf); FF(d, a, b, c, x[5], 12, 0x4787c62a); FF(c, d, a, b, x[6], 17, 0xa8304613); FF(b, c, d, a, x[7], 22, 0xfd469501); FF(a, b, c, d, x[8], 7, 0x698098d8); FF(d, a, b, c, x[9], 12, 0x8b44f7af); FF(c, d, a, b, x[10], 17, 0xffff5bb1); FF(b, c, d, a, x[11], 22, 0x895cd7be); FF(a, b, c, d, x[12], 7, 0x6b901122); FF(d, a, b, c, x[13], 12, 0xfd987193); FF(c, d, a, b, x[14], 17, 0xa679438e); FF(b, c, d, a, x[15], 22, 0x49b40821); GG(a, b, c, d, x[1], 5, 0xf61e2562); GG(d, a, b, c, x[6], 9, 0xc040b340); GG(c, d, a, b, x[11], 14, 0x265e5a51); GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); GG(a, b, c, d, x[5], 5, 0xd62f105d); GG(d, a, b, c, x[10], 9, 0x2441453); GG(c, d, a, b, x[15], 14, 0xd8a1e681); GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); GG(a, b, c, d, x[9], 5, 0x21e1cde6); GG(d, a, b, c, x[14], 9, 0xc33707d6); GG(c, d, a, b, x[3], 14, 0xf4d50d87); GG(b, c, d, a, x[8], 20, 0x455a14ed); GG(a, b, c, d, x[13], 5, 0xa9e3e905); GG(d, a, b, c, x[2], 9, 0xfcefa3f8); GG(c, d, a, b, x[7], 14, 0x676f02d9); GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); HH(a, b, c, d, x[5], 4, 0xfffa3942); HH(d, a, b, c, x[8], 11, 0x8771f681); HH(c, d, a, b, x[11], 16, 0x6d9d6122); HH(b, c, d, a, x[14], 23, 0xfde5380c); HH(a, b, c, d, x[1], 4, 0xa4beea44); HH(d, a, b, c, x[4], 11, 0x4bdecfa9); HH(c, d, a, b, x[7], 16, 0xf6bb4b60); HH(b, c, d, a, x[10], 23, 0xbebfbc70); HH(a, b, c, d, x[13], 4, 0x289b7ec6); HH(d, a, b, c, x[0], 11, 0xeaa127fa); HH(c, d, a, b, x[3], 16, 0xd4ef3085); HH(b, c, d, a, x[6], 23, 0x4881d05); HH(a, b, c, d, x[9], 4, 0xd9d4d039); HH(d, a, b, c, x[12], 11, 0xe6db99e5); HH(c, d, a, b, x[15], 16, 0x1fa27cf8); HH(b, c, d, a, x[2], 23, 0xc4ac5665); II(a, b, c, d, x[0], 6, 0xf4292244); II(d, a, b, c, x[7], 10, 0x432aff97); II(c, d, a, b, x[14], 15, 0xab9423a7); II(b, c, d, a, x[5], 21, 0xfc93a039); II(a, b, c, d, x[12], 6, 0x655b59c3); II(d, a, b, c, x[3], 10, 0x8f0ccc92); II(c, d, a, b, x[10], 15, 0xffeff47d); II(b, c, d, a, x[1], 21, 0x85845dd1); II(a, b, c, d, x[8], 6, 0x6fa87e4f); II(d, a, b, c, x[15], 10, 0xfe2ce6e0); II(c, d, a, b, x[6], 15, 0xa3014314); II(b, c, d, a, x[13], 21, 0x4e0811a1); II(a, b, c, d, x[4], 6, 0xf7537e82); II(d, a, b, c, x[11], 10, 0xbd3af235); II(c, d, a, b, x[2], 15, 0x2ad7d2bb); II(b, c, d, a, x[9], 21, 0xeb86d391); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } 客户端通过定义的规则将参数加密后,将密文和铭文参数同时传递到服务器,服务器收到参数进行解析,使用同样的加密算法将参数加密,然后对比此次得到的密文和客户端传递的密文是否相同,如果相同说明数据安全,没有被篡改,如果不同,则表示数据改变,不再发送数据到客户端 将加密方法打包到so库中的好处就是可以防止对方反编译看到我们的加密条件,如果对方不知道我们是如何加密的,也就可以在一定程度上防止数据泄漏,但是只是单纯的这样做并不能保证绝对的安全,比如,我不需要知道你是怎么加密的,只需要反编译apk后得到几个信息1.你应用的包名,2.你的so库,3.你的native方法 的完整类名和方法名(native方法不能被混淆,混淆后无法使用,所以可以得到),只要得到这三个信息,我就可以创建包名相同方法名相同的一个应用,把so放进去,然后就可以绕过密钥检查,轻松的调用你的接口了。 解决这个问题的方法就是在so库中加入签名验证,当调用加密方法对操作参数的时候,验证此时应用签名是否是我们本应用的,如果不是,则表示当前应用是伪应用,直接返回, 防止上边那种恶意调用接口情况的出现。对签名做校验,也就是只允许指定的应用可以使用,类似在微信支付中,也有在官方管理后台申请和配置应用的的签名和包名,否则就禁止使用,签名和包名必须得要一致。 com_app_rzm_utils_EncryptUtils.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_app_rzm_utils_Encryptils */ #ifndef _Included_com_app_rzm_utils_EncryptUtils #define _Included_com_app_rzm_utils_EncryptUtils #ifdef __cplusplus extern "C" { #endif /* * Class: com_app_rzm_utils_Encryptils * Method: encryptNative * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_app_rzm_utils_EncryptUtils_encryptNative (JNIEnv *, jclass, jobject ,jstring); JNIEXPORT void JNICALL Java_com_app_rzm_utils_EncryptUtils_checkSignature (JNIEnv *, jclass, jobject); #ifdef __cplusplus } #endif #endif encrypt.cpp #include "com_app_rzm_utils_EncryptUtils.h" #include "md5.h" #include <string> #include <android/log.h> using namespace std; #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"renzhenming",FORMAT,##__VA_ARGS__); #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"renzhenming",FORMAT,##__VA_ARGS__); //我们加密的方式是对参数进行md5加密,在md5加密之前还有一层加密,就是对参数字符串进行改造 //在字符串前加上自定义的key值,然后去掉字符串后边两位字符串,这个规则按需定制,增加破解的难度 #define MD5_KEY "renzhenming" //签名校验是否通过,否返回-1 static int signature_verify = -1; //app包名 static char* PACKAGE_NAME = "com.app.rzm"; //app签名,在这里配置我们app的正式签名,在so库中,可以保证安全性 static char* APP_SIGNATURE = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3137303332333033323030305a170d3437303331363033323030305a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d00308189028181008658a9a532d1c5e8c5a1a78c61535636220f73deb9b36d0912e2b6b1c50f5ed7eccb5cd8e0e4b2fd192d983fa15aeef6be5e5258e809b3fbad538fb68d1c78ebbdd89080664d707e9731c706386a45242a1e3a9e4819789bf832206a2bb7a45b663b6deb9be153ca4fe77b26ca1c43d85cbc20465cc6046f1e1dc16bbc65fe310203010001300d06092a864886f70d010105050003818100213550aa14811a7a407e7eb148b9cb50709c2c84185340b4c52f22caff07fd2e4a79e2814dc5a16fbd7a4b3ec638574eb5ee6baf7537b69aed6529a594bf556f1e0f073884739271f3e2572c4c174031b547846212643ae57bb35e8157c65b3760e37fc3c74f4e24daf3d91086d6ddd7a3f1e54b69ad235a6eb6c5524ce24800"; /** * @param env * @param jclazz * @param jparam * @return */ JNIEXPORT jstring JNICALL Java_com_app_rzm_utils_EncryptUtils_encryptNative (JNIEnv *env, jclass jclazz,jobject context,jstring jparam){ if(signature_verify == -1){ return env->NewStringUTF("EncryptUtils--> signature check err"); } const char *param = env->GetStringUTFChars(jparam,NULL); //在参数头位置加上MD5_KEY,然后去掉后面两位字符串 string signature_str(param); //insert(int p0, const char *s);在p0位置插入字符串s signature_str.insert(0,MD5_KEY); signature_str = signature_str.substr(0,signature_str.length()-2); //md5加密 MD5_CTX *ctx = new MD5_CTX(); MD5Init(ctx); MD5Update(ctx,(unsigned char *)signature_str.c_str(),signature_str.length()); unsigned char digest[16]; MD5Final(ctx, digest); int i = 0; char szMd5[32] = {0}; for(i = 0;i< 16 ; i++){ LOGI("EncryptUtils--> szMd5[%d]:%s",i,szMd5); //最终生成32位,不足前面补一位0 //x 表示以十六进制形式输出 ,02 表示不足两位,前面补0输出;出过两位,不影响 sprintf(szMd5,"%s%02x",szMd5,digest[i]); } env->ReleaseStringUTFChars(jparam,param); return env->NewStringUTF(szMd5); } JNIEXPORT void JNICALL Java_com_app_rzm_utils_EncryptUtils_checkSignature (JNIEnv *env, jclass jclazz, jobject context){ //1.获取包名 通过Context的getPackageName方法获取 //获取Context对象的class jclass context_class = env->GetObjectClass(context); //获取getPackageName的方法id jmethodID context_method_id = env->GetMethodID(context_class,"getPackageName","()Ljava/lang/String;"); //调用getPackageName方法 jstring package_name = (jstring)env->CallObjectMethod(context,context_method_id); //转换为char* const char *c_package_name = (char *)env->GetStringUTFChars(package_name,NULL); LOGI("EncryptUtils--> package name:%s\n",c_package_name); //2.对比包名 if(strcmp(c_package_name,PACKAGE_NAME)){ LOGI("EncryptUtils--> package name check err"); return; } //3.获取签名(通过下边这种方式) //PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); //Signature[] signatures = packageInfo.signatures; //LogUtils.d("signature:"+signatures[0].toCharsString()); //获取Context中的getPackageManager方法id jmethodID get_package_manager_method_id = env->GetMethodID(context_class,"getPackageManager","()Landroid/content/pm/PackageManager;"); //从Context中通过调用getPackageManager获取PackageManager对象 jobject package_manager = env->CallObjectMethod(context,get_package_manager_method_id); //获取PackageManager对象的class jclass package_manager_class = env->GetObjectClass(package_manager); //获取PackageManager对象中的getPackageInfo方法id jmethodID get_package_info_method_id = env->GetMethodID(package_manager_class,"getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); //调用PackageInfo中的getPackageInfo方法获取PackageInfo对象(PackageManager.GET_SIGNATURES=64) jobject package_manager_info = env->CallObjectMethod(package_manager,get_package_info_method_id,package_name,64); //获取PackageInfo的class,获取它的属性的时候要用到 jclass package_info_class = env->GetObjectClass(package_manager_info); //获取PackageInfo中的signatures属性的fieldid jfieldID signatures_field_id = env->GetFieldID(package_info_class,"signatures","[Landroid/content/pm/Signature;"); //获取PackageInfo中的signatures属性 jobjectArray signatures_arrary = (jobjectArray) env->GetObjectField(package_manager_info, signatures_field_id); //获取数组中[0]位置的元素 jobject signature = env->GetObjectArrayElement(signatures_arrary,0); //获取String的class jclass signature_class = env->GetObjectClass(signature); //获取String中的toCharsString方法的methodid jmethodID to_chars_string_method_id = env->GetMethodID(signature_class,"toCharsString","()Ljava/lang/String;"); //调用String的toCharsString jstring signature_string = (jstring) env->CallObjectMethod(signature, to_chars_string_method_id); //转换为char* const char * signature_char = env->GetStringUTFChars(signature_string,NULL); LOGI("EncryptUtils--> current app signature:%s\n",signature_char); LOGI("EncryptUtils--> real app signature:%s\n",APP_SIGNATURE); //4.对比签名 if(strcmp(signature_char,APP_SIGNATURE) == 0){ signature_verify = 1; LOGI("EncryptUtils--> signature_verify success:%d\n",signature_verify); }else{ signature_verify = -1; LOGI("EncryptUtils--> signature_verify check failed:%d\n",signature_verify); } } 总结一下: 我们通过使用纯c++代码实现md5加密,将加密实现方式打包成so库,提高反编译的难度,另外在md5加密之外我们还设置了另一层加密规则,对参数字符串头尾进行处理,双层加密,确保数据的安全性。在加密手段之外,再进行app包名和签名的校验,从而保证so库只能在我们自己的app中使用。三层保护,这样一来,相信即便是遇到逆向工程师,要破解我们的app也是有一定难度的。

优秀的个人博客,低调大师

07.Android Studio下Ndk开发(使用fmod播放声音)

(创建于2017/12/28) 已实现 注意几点: 1.main下cpp文件夹放置c文件和相关头文件 2.main下JniLibs文件夹放置第三方so文件 3.app下libs文件夹放置jar包 4.CMakeLists配置文件: cmake_minimum_required(VERSION 3.4.1) add_library( //打包多个cpp文件为同一个so文件qq_voice qq_voice SHARED src/main/cpp/common.cpp src/main/cpp/play_sound.cpp src/main/cpp/common_platform.cpp ) //引入第三方 add_library( libfmod SHARED IMPORTED ) //配置第三方路径 set_target_properties( libfmod PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libfmod.so ) //引入第三方 add_library( libfmodL SHARED IMPORTED ) //配置第三方路径 set_target_properties( libfmodL PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libfmodL.so ) find_library( log-lib log ) target_link_libraries( qq_voice libfmod libfmodL ${log-lib} ) 5.build.gradle文件配置 android { compileSdkVersion 26 buildToolsVersion "26.0.0" defaultConfig { ... externalNativeBuild { cmake { cppFlags "" } } ndk { //和JniLibs下的api相对应,不然会报错 abiFilters 'armeabi', 'armeabi-v7a','arm64-v8a','x86' } } ... externalNativeBuild { cmake { //配置CMakeLists文件路径 path 'CMakeLists.txt' } } }

优秀的个人博客,低调大师

android studio build.gradle中 project.ANDROID_BUILD_SDK_VERSION

1.メニューの [File] -> [Import Module] 2.Source directory に先ほど解凍したディレクトリを指定 3.「facebook」 を選択した状態に Finish すると以下のようなエラーが発生 Error:(9, 0) Could not find property 'ANDROID_BUILD_SDK_VERSION' on project ':facebook'. これは、facebook/build.gradleで以下が記述されているため project.ANDROID_BUILD_SDK_VERSION project.ANDROID_BUILD_TOOLS_VERSION project.ANDROID_BUILD_MIN_SDK_VERSION project.ANDROID_BUILD_TARGET_SDK_VERSION facebook/build.gradle apply plugin: 'android-library' dependencies { compile 'com.android.support:support-v4:19.1.+' compile 'com.parse.bolts:bolts-android:1.1.2' } android { compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION defaultConfig { minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION) targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) } lintOptions { abortOnError false } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] res.srcDirs = ['res'] } } } なので、gradle.propertiesに以下を追記し sync ANDROID_BUILD_SDK_VERSION=18 ANDROID_BUILD_TOOLS_VERSION=20 ANDROID_BUILD_MIN_SDK_VERSION=15 ANDROID_BUILD_TARGET_SDK_VERSION=18 分类: android solve 本文转自wanqi博客园博客,原文链接http://www.cnblogs.com/wanqieddy/p/4432150.html如需转载请自行联系原作者

优秀的个人博客,低调大师

(转)Android Studio Error:Failed to resolve: com.android.support:appcomp...

今天不知道为什么导入eclipse项目后就出现了错误,没导入之前是正常使用AS的 Error:(26, 13) Failed to resolve: com.android.support:appcompat-v7:25.+ 第一、点击Install Repository 。 但是Installing Android Support Repository失败了 当然还是可以在SDK那里进行相应版本的安装API 第二、点击Show in Project Structure dialog 更改自己Compile sdk Version 选择合适的API 同时更改自己budle.gradle 更改compile合适的support 如果还是有问题更改gradle设置(选择自己安装AS的目录文件)如图 第三、下载http://services.gradle.org/distributions/gradle-2.4-all.zip 这个版本,下载好的zip文件解压到AS安装目录的gradle目录下或者放在 C:\Users\cq.gradle\wrapper\dists\gradle-2.4-all*************** 这个文件夹里, 不需要解压。 我的问题是通过第二种方法解决的。。。

优秀的个人博客,低调大师

Android Studio - 第四十八期 模块ViewPager+Fragment

最近一直在review撸撸的代码,发现了一种模块的写法,非常不错,独立出来,希望能帮到你~ 如果你遇到这样的页面,怎么办,不会把所有代码都写到一个页面中吧~,这样看你代码的人会骂死你的吧~我想~而且如果不同的版本要用不同的位置,大小也不一样,难道你要重新布局嘛~这都是开发中需要纠结的,下面就开始正题了,这是利用了以前讲过的多版本打版以及配置多Fragment加载巧妙的解决了复杂的页面逻辑,我数了数,首页代码不到一百行,厉害吧~哈哈哈哈~ 在写这样的页面之前给大家介绍一下怎么写一个页面模块代码。 demo1:单Activity页面多模块单版本 Demo1FragmentFactory: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.example.p031_mokuaihua_viewpager_fragment.demo1.factorys; import android.support.v4.util.SparseArrayCompat; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo1.fragments.Demo1Fragment1; import com.example.p031_mokuaihua_viewpager_fragment.demo1.fragments.Demo1Fragment2; /** *Createdbyshiningon2017/2/270027. */ public class Demo1FragmentFactory{ private static SparseArrayCompat<Class<? extends BaseFragment>>sIndexFragments= new SparseArrayCompat<>(); static { sIndexFragments.put(R.id.demo1_page_0_item_0,Demo1Fragment1. class ); //模块1 sIndexFragments.put(R.id.demo1_page_0_item_1,Demo1Fragment2. class ); //模块2 } public static Class<? extends BaseFragment>get( int id){ if (sIndexFragments.indexOfKey(id)< 0 ){ throw new UnsupportedOperationException( "cannotfindfragmentby" +id); } return sIndexFragments.get(id); } public static SparseArrayCompat<Class<? extends BaseFragment>>get(){ return sIndexFragments; } } ComFragmentHelper: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 package com.example.p031_mokuaihua_viewpager_fragment.utils; import android.os.Bundle; import android.support.v4.app.Fragment; /** *Createdbyshiningon2016/12/210021. */ public class ComFragmentHelper{ /** *新建fragment实例 *@paramfragmentKlass *@parambundle *@param<T> *@return */ @SuppressWarnings ( "unchecked" ) public static <T extends Fragment>TnewFragment(Class<T>fragmentKlass,Bundlebundle){ Tres= null ; try { res=fragmentKlass.newInstance(); if (bundle!= null ){ res.setArguments(bundle); } } catch (InstantiationExceptione){ e.printStackTrace(); } catch (IllegalAccessExceptione){ e.printStackTrace(); } return res; } /** *根据fragment的完整包名+名称实例化fragment *@paramclassName *@parambundle *@param<T> *@return */ @SuppressWarnings ( "unchecked" ) public static <T extends Fragment>TnewFragment(StringclassName,Bundlebundle){ Tres= null ; try { res=(T)Class.forName(className).newInstance(); if (bundle!= null ){ res.setArguments(bundle); } } catch (InstantiationExceptione){ e.printStackTrace(); } catch (IllegalAccessExceptione){ e.printStackTrace(); } catch (ClassNotFoundExceptione){ e.printStackTrace(); } return res; } } Demo1Fragment1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.example.p031_mokuaihua_viewpager_fragment.demo1.fragments; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexNetFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo1.Demo1Activity; /** *Createdbyshiningon2017/8/14. */ public class Demo1Fragment1 extends BaseIndexNetFragment{ @Override public void call(Objectvalue){ } @Override protected int getLayoutId(){ return R.layout.activity_demo1_fragment1; } @Override protected void setup(ViewrootView, @Nullable BundlesavedInstanceState){ super .setup(rootView,savedInstanceState); rootView.findViewById(R.id.tv1).setOnClickListener( new View.OnClickListener(){ @Override public void onClick(Viewv){ SendToFragment( "demo1的fragment1页面" ); } }); } /** *页面传值操作部分 * *@paramid1 */ private void SendToFragment(Stringid1){ //举例 //IndexFoodFragmentUpdateIdsiff=newIndexFoodFragmentUpdateIds(); //iff.setFood_definition_id(id1); //iff.setFood_name(id2); if (getActivity()!= null &&getActivity() instanceof Demo1Activity){ ((Demo1Activity)getActivity()).callFragment(id1,Demo1Fragment2. class .getName()); } } } Demo1Fragment2: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.example.p031_mokuaihua_viewpager_fragment.demo1.fragments; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexNetFragment; import com.example.p031_mokuaihua_viewpager_fragment.utils.ToastUtil; /** *Createdbyshiningon2017/8/14. */ public class Demo1Fragment2 extends BaseIndexNetFragment{ @Override public void call(Objectvalue){ Stringids=(String)value; ToastUtil.showToastShort(ids); } @Override protected int getLayoutId(){ return R.layout.activity_demo1_fragment2; } @Override protected void setup(ViewrootView, @Nullable BundlesavedInstanceState){ super .setup(rootView,savedInstanceState); } } 这里注意Fragment之间如果需要通信,可以用下面的方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /** *页面传值操作部分 * *@paramid1 */ private void SendToFragment(Stringid1){ //举例 //IndexFoodFragmentUpdateIdsiff=newIndexFoodFragmentUpdateIds(); //iff.setFood_definition_id(id1); //iff.setFood_name(id2); if (getActivity()!= null &&getActivity() instanceof Demo1Activity){ ((Demo1Activity)getActivity()).callFragment(id1,Demo1Fragment2. class .getName()); } } //接收传值处理逻辑bufen @Override public void call(Objectvalue){ Stringids=(String)value; ToastUtil.showToastShort(ids); } Demo1Activity: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 package com.example.p031_mokuaihua_viewpager_fragment.demo1; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.util.SparseArrayCompat; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseActivity; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo1.factorys.Demo1FragmentFactory; import com.example.p031_mokuaihua_viewpager_fragment.utils.ComFragmentHelper; public class Demo1Activity extends BaseActivity implements OnClickListener{ @Override protected int getLayoutId(){ return R.layout.activity_demo1; } @Override protected void setup( @Nullable BundlesavedInstanceState){ super .setup(savedInstanceState); findview(); onclickListener(); doNetWork(); } private void doNetWork(){ } private void onclickListener(){ } private void findview(){ setupFragments(); } /** *初始化首页fragments */ private void setupFragments(){ FragmentTransactionft=getSupportFragmentManager().beginTransaction(); SparseArrayCompat<Class<? extends BaseFragment>>array=Demo1FragmentFactory.get(); //一个版本模式bufen int size=array.size(); BaseFragmentitem; for ( int i= 0 ;i<size;i++){ item=ComFragmentHelper.newFragment(array.valueAt(i), null ); ft.replace(array.keyAt(i),item,item.getClass().getName()); } ft.commitAllowingStateLoss(); } @Override public void onClick(Viewv){ } /** *fragment间通讯bufen * *@paramvalue要传递的值 *@paramtag要通知的fragment的tag */ public void callFragment(Objectvalue,String...tag){ FragmentManagerfm=getSupportFragmentManager(); Fragmentfragment; for (Stringitem:tag){ if (TextUtils.isEmpty(item)){ continue ; } fragment=fm.findFragmentByTag(item); if (fragment!= null &&fragment instanceof BaseIndexFragment){ ((BaseIndexFragment)fragment).call(value); } } } } 效果如下图: demo2:单Activity页面多模块多版本 Demo2Config1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 package com.example.p031_mokuaihua_viewpager_fragment.demo2.configs; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.support.v4.util.SparseArrayCompat; import android.text.TextUtils; import com.example.p031_mokuaihua_viewpager_fragment.applications.DemoApplication; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.utils.MyLogUtil; /** *<p>function:</p> *<p>description:</p> *<p>history:1.2017/3/23</p> *<p>Author:geek</p> *<p>modification:</p> */ public class Demo2Config1{ private static final StringINDEX_META_DATA= "DEMO2_CONFIG" ; /**viewpager页大小*/ //publicstaticintPAGE_COUNT; /**viewpager每页的itemviewid*/ //publicstaticStringPAGE_ID; /**默认显示第几页*/ //publicstaticintDEFAULT_PAGE_INDEX; /** *fragment配置 */ private static SparseArrayCompat<Class<? extends BaseFragment>>sIndexFragments= new SparseArrayCompat<>(); public static void config(){ Contextctx=DemoApplication.get(); ApplicationInfoinfo= null ; try { info=ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundExceptione){ e.printStackTrace(); } if (info== null ){ throw new UnsupportedOperationException(); } StringklassName=info.metaData.getString(INDEX_META_DATA); if (TextUtils.isEmpty(klassName)){ throw new UnsupportedOperationException( "pleaseconfig" +INDEX_META_DATA+ "value" ); } if (klassName.startsWith( "." )){ klassName=DemoApplication.get().getPackageName()+klassName; } MyLogUtil.d( "geek" ,klassName); try { Class<?>klass=Class.forName(klassName); klass.getDeclaredMethod( "setup" ).invoke( null ); } catch (Exceptione){ e.printStackTrace(); } } public static Class<? extends BaseFragment>getFragment( int id){ if (sIndexFragments.indexOfKey(id)< 0 ){ throw new UnsupportedOperationException( "cannotfindfragmentby" +id); } return sIndexFragments.get(id); } public static SparseArrayCompat<Class<? extends BaseFragment>>getFragments(){ return sIndexFragments; } } Demo2Factory1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.example.p031_mokuaihua_viewpager_fragment.demo2.factorys; import android.support.v4.util.SparseArrayCompat; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo2.configs.Demo2Config1; import com.example.p031_mokuaihua_viewpager_fragment.demo2.fragments.Demo2Fragment1; import com.example.p031_mokuaihua_viewpager_fragment.demo2.fragments.Demo2Fragment2; public class Demo2Factory1{ public static void setup(){ //IndexConfig.PAGE_COUNT=3; //IndexConfig.PAGE_ID="old_pager_index_"; //IndexConfig.DEFAULT_PAGE_INDEX=1; registerFragments(Demo2Config1.getFragments()); } private static void registerFragments(SparseArrayCompat<Class<? extends BaseFragment>>sIndexFragments){ sIndexFragments.put(R.id.demo2_page_0_item_1,Demo2Fragment1. class ); //菜谱 sIndexFragments.put(R.id.demo2_page_0_item_2,Demo2Fragment2. class ); //视频 } } build.gradle:(多版本打版) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 defcurrentMode=flavor.versionName.split( "_" )[ 3 ] defcurrentEnvironment=flavor.versionName.split( "_" )[ 1 ] defstValue= true //t==currentEnvironment以前的判断条件 if (currentEnvironment.endsWith( "T" )){ //判断是否为测试版是否以T结尾 stValue= false } else { stValue= true } if (currentMode==demo1){ flavor.manifestPlaceholders=[DEMO2_CONFIG_VALUE: ".demo2.factorys.Demo2Factory1" ,STATISTICS_VALUE:stValue] } else if (currentMode==demo2){ flavor.manifestPlaceholders=[DEMO2_CONFIG_VALUE: ".demo2.factorys.Demo2Factory2" ,STATISTICS_VALUE:stValue] } Demo2Activity: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 package com.example.p031_mokuaihua_viewpager_fragment.demo2; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.util.SparseArrayCompat; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.applications.ConstantNetUtil; import com.example.p031_mokuaihua_viewpager_fragment.applications.NetConfig; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseActivity; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo2.configs.Demo2Config1; import com.example.p031_mokuaihua_viewpager_fragment.demo2.configs.Demo2Config2; import com.example.p031_mokuaihua_viewpager_fragment.utils.ComFragmentHelper; public class Demo2Activity extends BaseActivity implements OnClickListener{ @Override protected void onCreate(BundlesavedInstanceState){ if (ConstantNetUtil.VERSION_APK==NetConfig.version_name1){ Demo2Config1.config(); } else if (ConstantNetUtil.VERSION_APK==NetConfig.version_name2){ Demo2Config2.config(); } super .onCreate(savedInstanceState); setupFragments(); findview(); onclickListener(); doNetWork(); } @Override protected int getLayoutId(){ return R.layout.activity_demo2; } @Override protected void setup( @Nullable BundlesavedInstanceState){ super .setup(savedInstanceState); //setupFragments(); //findview(); //onclickListener(); //doNetWork(); } /** *初始化首页fragments */ private void setupFragments(){ FragmentTransactionft=getSupportFragmentManager().beginTransaction(); //TODO多版本模式bufen SparseArrayCompat<Class<? extends BaseFragment>>array=which_version_fragment_config(); // int size=array.size(); BaseFragmentitem; for ( int i= 0 ;i<size;i++){ item=ComFragmentHelper.newFragment(array.valueAt(i), null ); ft.replace(array.keyAt(i),item,item.getClass().getName()); } ft.commitAllowingStateLoss(); } private SparseArrayCompat<Class<? extends BaseFragment>>which_version_fragment_config(){ if (ConstantNetUtil.VERSION_APK==NetConfig.version_name1){ return Demo2Config1.getFragments(); } else if (ConstantNetUtil.VERSION_APK==NetConfig.version_name2){ return Demo2Config2.getFragments(); } return Demo2Config1.getFragments(); } private void doNetWork(){ } private void onclickListener(){ } private void findview(){ } @Override public void onClick(Viewv){ } /** *fragment间通讯bufen * *@paramvalue要传递的值 *@paramtag要通知的fragment的tag */ public void callFragment(Objectvalue,String...tag){ FragmentManagerfm=getSupportFragmentManager(); Fragmentfragment; for (Stringitem:tag){ if (TextUtils.isEmpty(item)){ continue ; } fragment=fm.findFragmentByTag(item); if (fragment!= null &&fragment instanceof BaseIndexFragment){ ((BaseIndexFragment)fragment).call(value); } } } } 效果如下图: 下面就是最复杂的一种需求:demo3单Activity页面多模块单版本两个Viewpager Demo3Config: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 package com.example.p031_mokuaihua_viewpager_fragment.demo3.configs; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.support.v4.util.SparseArrayCompat; import android.text.TextUtils; import com.example.p031_mokuaihua_viewpager_fragment.applications.DemoApplication; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.utils.MyLogUtil; public class Demo3Config{ private static final StringINDEX_META_DATA= "DEMO3_CONFIG" ; /**viewpager页大小*/ public static int PAGE_COUNT; /**viewpager每页的itemviewid*/ public static StringPAGE_LAYOUT_ID; /**默认显示第几页*/ public static int DEFAULT_PAGE_INDEX; /** *fragment配置 */ private static SparseArrayCompat<Class<? extends BaseFragment>>sIndexFragments= new SparseArrayCompat<>(); public static void config(){ Contextctx=DemoApplication.get(); ApplicationInfoinfo= null ; try { info=ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundExceptione){ e.printStackTrace(); } if (info== null ){ throw new UnsupportedOperationException(); } StringklassName=info.metaData.getString(INDEX_META_DATA); if (TextUtils.isEmpty(klassName)){ throw new UnsupportedOperationException( "pleaseconfig" +INDEX_META_DATA+ "value" ); } if (klassName.startsWith( "." )){ klassName=DemoApplication.get().getPackageName()+klassName; } MyLogUtil.d( "geek" ,klassName); try { Class<?>klass=Class.forName(klassName); klass.getDeclaredMethod( "setup" ).invoke( null ); } catch (Exceptione){ e.printStackTrace(); } } public static Class<? extends BaseFragment>getFragment( int id){ if (sIndexFragments.indexOfKey(id)< 0 ){ throw new UnsupportedOperationException( "cannotfindfragmentby" +id); } return sIndexFragments.get(id); } public static SparseArrayCompat<Class<? extends BaseFragment>>getFragments(){ return sIndexFragments; } } Demo3Factory: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.example.p031_mokuaihua_viewpager_fragment.demo3.factorys; import android.support.v4.util.SparseArrayCompat; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo3.configs.Demo3Config; import com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments.Demo3Fragment10; import com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments.Demo3Fragment11; import com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments.Demo3Fragment20; import com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments.Demo3Fragment21; /** *首页模块fragment的工厂,首页模块有需要更换的,可以在此修改,格式为id->Fragment.class<br/> *Createdbyshiningon2016/8/1. */ public class Demo3Factory{ public static void setup(){ Demo3Config.PAGE_COUNT= 2 ; Demo3Config.PAGE_LAYOUT_ID= "activity_demo3_layout_pager_item_" ; Demo3Config.DEFAULT_PAGE_INDEX= 0 ; registerFragments(Demo3Config.getFragments()); } private static void registerFragments(SparseArrayCompat<Class<? extends BaseFragment>>sIndexFragments){ sIndexFragments.put(R.id.fragment_demo3_pager_index_0_0,Demo3Fragment10. class ); //第一屏layout1 sIndexFragments.put(R.id.fragment_demo3_pager_index_0_1,Demo3Fragment11. class ); //第一屏layout2 sIndexFragments.put(R.id.fragment_demo3_pager_index_1_0,Demo3Fragment20. class ); //第二屏layout1 sIndexFragments.put(R.id.fragment_demo3_pager_index_1_1,Demo3Fragment21. class ); //第二屏layout2 } } Demo3Fragment10: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexNetFragment; import com.example.p031_mokuaihua_viewpager_fragment.demo3.Demo3Activity; /** *Createdbyshiningon2017/8/14. */ public class Demo3Fragment10 extends BaseIndexNetFragment{ private ContextmContext; @Override public void onCreate( @Nullable Bundlebundle){ super .onCreate(bundle); mContext=getActivity(); } @Override public void call(Objectvalue){ } @Override protected int getLayoutId(){ return R.layout.activity_demo3_fragment10; } @Override protected void setup(ViewrootView, @Nullable BundlesavedInstanceState){ super .setup(rootView,savedInstanceState); rootView.findViewById(R.id.tv1).setOnClickListener( new View.OnClickListener(){ @Override public void onClick(Viewv){ SendToFragment( "demo3的fragment1页面" ); ((Demo3Activity)mContext).changeView( 1 ); } }); } /** *页面传值操作部分 * *@paramid1 */ private void SendToFragment(Stringid1){ //举例 //IndexFoodFragmentUpdateIdsiff=newIndexFoodFragmentUpdateIds(); //iff.setFood_definition_id(id1); //iff.setFood_name(id2); if (getActivity()!= null &&getActivity() instanceof Demo3Activity){ ((Demo3Activity)getActivity()).callFragment(id1,Demo3Fragment20. class .getName()); } } } Demo3Fragment20: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.example.p031_mokuaihua_viewpager_fragment.demo3.fragments; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import com.example.p031_mokuaihua_viewpager_fragment.R; import com.example.p031_mokuaihua_viewpager_fragment.base.BaseIndexNetFragment; import com.example.p031_mokuaihua_viewpager_fragment.utils.ToastUtil; /** *Createdbyshiningon2017/8/14. */ public class Demo3Fragment20 extends BaseIndexNetFragment{ @Override public void call(Objectvalue){ Stringids=(String)value; ToastUtil.showToastShort(ids); } @Override protected int getLayoutId(){ return R.layout.activity_demo3_fragment20; } @Override protected void setup(ViewrootView, @Nullable BundlesavedInstanceState){ super .setup(rootView,savedInstanceState); } } 这里的导航点也可以自定义:给大家提供一个util 有圆的 方的 长方形 水滴 IndexPagerIndicator: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 package com.example.p031_mokuaihua_viewpager_fragment.demo3.utils; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; import com.example.p031_mokuaihua_viewpager_fragment.R; /** *首页viewpager指示符<br/> *Createdbygeekon2016/7/29. */ public class IndexPagerIndicator extends LinearLayout{ private int mItemWidth; private int mItemSelectedHeight; private int mItemInterval; private int mItemColor; private int mStartX; private int mCurrentX; private PaintmSelectedPaint; private IStyleDrawermStyleDrawer; public IndexPagerIndicator(Contextcontext){ this (context, null , 0 ); } public IndexPagerIndicator(Contextcontext,AttributeSetattrs){ this (context,attrs, 0 ); } public IndexPagerIndicator(Contextcontext,AttributeSetattrs, int defStyleAttr){ super (context,attrs,defStyleAttr); setBackgroundColor(Color.TRANSPARENT); setOrientation(LinearLayout.HORIZONTAL); TypedArrayta=context.obtainStyledAttributes(attrs,R.styleable.IndexPagerIndicator,defStyleAttr, 0 ); mItemWidth=ta.getDimensionPixelSize(R.styleable.IndexPagerIndicator_indicator_width, 10 ); int itemHeight=ta.getDimensionPixelSize(R.styleable.IndexPagerIndicator_indicator_height, 2 ); mItemSelectedHeight=ta.getDimensionPixelSize(R.styleable.IndexPagerIndicator_indicator_select_height, 0 ); if (mItemSelectedHeight== 0 ){mItemSelectedHeight=itemHeight;} mItemInterval=ta.getDimensionPixelSize(R.styleable.IndexPagerIndicator_indicator_interval, 0 ); mItemColor=ta.getColor(R.styleable.IndexPagerIndicator_indicator_item_color,Color.BLACK); int selectedColor=ta.getColor(R.styleable.IndexPagerIndicator_indicator_select_color,Color.WHITE); StringstyleDrawer=ta.getString(R.styleable.IndexPagerIndicator_indicator_style_drawer); try { if (TextUtils.isEmpty(styleDrawer)){ throw new Exception(); } mStyleDrawer=(IStyleDrawer)Class.forName(styleDrawer).newInstance(); } catch (Exceptione){ e.printStackTrace(); mStyleDrawer= new DefaultStyleDrawer(); } ta.recycle(); mStyleDrawer.prepare(mItemWidth,itemHeight,mItemSelectedHeight); mSelectedPaint= new Paint(Paint.ANTI_ALIAS_FLAG); mSelectedPaint.setColor(selectedColor); } @Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec){ super .onMeasure(widthMeasureSpec,heightMeasureSpec); if (mItemSelectedHeight>getMeasuredHeight()){ setMeasuredDimension(getMeasuredWidth(),mItemSelectedHeight); } mStartX=(getMeasuredWidth()-(getChildCount()*mItemWidth

优秀的个人博客,低调大师

Android Studio 第五十一期 - 自定义RecycleView Gallery

代码已经整理好,效果如下图:(支持Verical Horizontal 支持自定义放大位置 支持滚动速度) 图片1: 图片2: 地址: https://github.com/geeklx/MyApplication/tree/master/p010_recycleviewall/src/main/java/com/shining/p010_recycleviewall/recycleviewgalleryhorizontal 本文转自 吴雨声 51CTO博客,原文链接:http://blog.51cto.com/liangxiao/1963789,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android Pro] Android studio jni中调用Log输出调试信息

reference to :http://www.linuxidc.com/Linux/2014-02/96341.htm Android开发中,java 可以方便的使用调试信息Log.i, Log.d ...,Jni层可否使用呢?答案是肯定的。 1 为方便使用,先进行宏定义: eben_hpc_log.h内容如下: #ifndef _Included_hpc_Log #define _Included_hpc_Log #ifdef __cplusplus extern "C" { #endif #include <android/log.h> // 宏定义类似java 层的定义,不同级别的Log LOGI, LOGD, LOGW, LOGE, LOGF。 对就Java中的 Log.i log.d #define LOG_TAG "hpc -- JNILOG" // 这个是自定义的LOG的标识 //#undef LOG // 取消默认的LOG #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG, __VA_ARGS__) #ifdef __cplusplus } #endif #endif 2 代码中使用: //demo.c #include <jni.h> #include "eben_hpc_log.h" JNIEXPORT jint JNICALL Java_cn_hpc_cai_jni_JniLogDemo_test(JNIEnv* env,jobject jobj) { LOGD("log.d 这是Jni中的log: Java_cn_hpc_cai_jni_JniLogDemo_test()"); LOGI("Log.i 这是Jni中的log: Java_cn_hpc_cai_jni_JniLogDemo_test()"); return 0; } 3 app/build.gradle 中 1 2 3 4 5 6 7 8 defaultConfig { ndk { ldLibs "log" moduleName "xal" //生成的so名字 abiFilters "armeabi" //输出指定三种abi体系结构下的so库。目前可有可无。 //abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。目前可有可无。 } } 接下来就是 Java层的调用: 4 java 调用 public static final String libName = "xal"; static { System.loadLibrary(libName); } { JniLogDemo demo = new JniLogDemo(); demo.test(); } 完毕。 分类: Android Pro 本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/p/5628291.html如需转载请自行联系原作者 demoblog

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册