从Android Studio迁移到IntelliJ,从Gradle2升级到Gradle5.4.1,JNI NDK的配置更新

IntelliJ IDEA,是java编程语言开发的集成环境,在业界被公认为最好的java开发工具之一。参考其官网:https://www.jetbrains.com/idea/。

其实不只是Java,同家公司的Android Studio、PHPStorm、WebStorm、PyCharm、RubyMine的功能,它都有,不就是插件嘛!所以,最近把Android Studio、PHPStorm、WebStorm、PyStorm全部干掉了,所有项目都用IntelliJ来开发。

因为IntelliJ的各种插件都比较新,所以,顺带把Android的各种编译工具和环境更新到相对新的版本,也就有了如下采坑总结,记录一下。

1.gradle.properties

#gradle:3.0.1  studio3.0 之前用
#android.useDeprecatedNdk=true
#gradle:3.0.1  studio3.0 之后用
#android.deprecatedNdkCompileLease=1511832698813
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

2.根目录下的:build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        google()
//        jcenter {
//            url "http://jcenter.bintray.com/"
//        }
    }
    dependencies {
//        classpath 'com.android.tools.build:gradle:2.1.3'
        classpath 'com.android.tools.build:gradle:3.5.0'
        classpath 'com.mob.sdk:MobSDK:+'
        classpath 'com.mob.sdk:MobSDK-Impl:2018.0710.1743'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com"
        }
        maven {
            url 'https://dl.bintray.com/youzanyun/maven/'
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

3.library目录下的:build.gradle

apply plugin: 'com.android.library'

android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    lintOptions {
        abortOnError false
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

}

4.子项目的build.gradle


android {
    dexOptions {
        preDexLibraries = false
        javaMaxHeapSize "4g"
    }

    externalNativeBuild {
        ndkBuild {
            path "src/main/jni/Android.mk" // 设置所要编写的c源码位置,以及编译后so文件的名字
        }
    }

    compileOptions {
        encoding = "UTF-8"
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

    signingConfigs {

        release {
            keyAlias '***'
            keyPassword '***'
            storeFile file('../***')
            storePassword '***'
        }
    }
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }

    compileSdkVersion 28

    defaultConfig {
        applicationId "com.threeti.huimapatient"
        multiDexEnabled true
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 800
        versionName "8.0.0"

        // 下面这段是老版本的写法,不需要了
//        ndk {
//            moduleName "JniAES"
//            ldLibs "log", "z", "m"
//            abiFilters "armeabi-v7a", "x86"
//        }
        // 使用ndkBuild工具
        externalNativeBuild {
            ndkBuild {
                //指定 Application.mk 的路径
                arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk"
                //指定生成哪些平台的 so 文件
                //abiFilters "armeabi-v7a", "armeabi"
                //生成多个版本的so文件
                abiFilters "armeabi-v7a", "x86"
                //cFlags 和 cppFlags 是用来设置环境变量的, 一般不需要动
                cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2"
                cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2"
                //cppFlags ""
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.release

            applicationVariants.all { variant ->
                variant.outputs.all {
                    outputFileName = "YOURAPPNAME_release_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                }
            }
        }
    }

    sourceSets {
        main {
            jni.srcDirs = ['src/main/jni','src/main/jni/']
            jniLibs.srcDir 'src/main/libs'
        }
    }

    // Specifies the flavor dimensions you want to use. The order in which you
    // list each dimension determines its priority, from highest to lowest,
    // when Gradle merges variant sources and configurations. You must assign
    // each product flavor you configure to one of the flavor dimensions.
    flavorDimensions "default"//,"mode","version","api"

    productFlavors {
        xiaomi { // Assigns this product flavor to the "mode" flavor dimension.
            dimension "default"
        }
        yingyongbao { // Assigns this product flavor to the "mode" flavor dimension.
            dimension "default"
        }
        huawei { // Assigns this product flavor to the "mode" flavor dimension.
            dimension "default"
        }

        // 这里需要这个配置是因为,我们上面虽然建立了渠道,但是并没有处理Manifest里面的meta-data信息。
        productFlavors.all { flavor ->
            flavor.manifestPlaceholders = [UMENG_CHANNEL: name] //动态地修改AndroidManifest中的渠道名
        }
    }
    useLibrary 'org.apache.http.legacy'
}

repositories {
    flatDir {
        dirs 'libs'
    }
    mavenCentral()
}


dependencies {
    implementation 'in.srain.cube:ultra-ptr:1.0.11'
    implementation files('libs/universal-image-loader-1.9.3.jar')
    implementation (name: 'alipaySdk-15.6.8-20191021122455-noUtdid', ext: 'aar')
    ...
}

5.对应的android.mk

LOCAL_PATH := $(call my-dir)

# Builds a dylib out of test.cpp
# 会清除很多 LOCAL_XXX 变量,不会清除 LOCAL_PATH,基本上是固定的,不需要去动
include $(CLEAR_VARS)
# 需要构建模块的名称,会自动生成相应的 libNDKSample.so 文件,每个模块名称必须唯一,且不含任何空格
LOCAL_MODULE := JniAES
# 包含要构建到模块中的 C 或 C++ 源文件列表
LOCAL_SRC_FILES := KeyValue.c
# 指定这个模块里会用到哪些原生 API,详见:https://developer.android.google.cn/ndk/guides/stable_apis.html
LOCAL_LDLIBS := -llog
# 帮助系统将所有内容连接到一起,固定的,不需要去动
include $(BUILD_SHARED_LIBRARY)

6.对应的Application.mk

# https://developer.android.com/ndk/guides/application_mk.html
# 选择不同的 ABI,多个使用空格作为分隔符,全部是all
APP_ABI := all # armeabi-v7a x86
# 指定要使用的运行时
APP_STL := system

参考:

https://developer.android.com/ndk/guides/android_mk

https://www.cnblogs.com/webor2006/p/9999063.html

http://wuxiaolong.me/2017/12/27/AndroidNDK/

Android安卓上用代码实现设置圆角radius的颜色背景

Android经常会使用shape来定制一些View的背景,可以修改View的背景颜色,形状等属性。一般情况下,shape都是在xml文件里面实现,比如:

<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#1d3c80" />
    <corners android:radius="@dimen/dim30" />
</shape>

继续阅读“Android安卓上用代码实现设置圆角radius的颜色背景”

android TextView autolink的用法——自动识别电话|网址|邮件

1. 通用的方法

textView.setAutoLinkMask(Linkify.ALL);
或者在xml布局文件中 android:autoLink=”all”

2. 带正则式的识别方法,超过五位数字默认为手机号

Pattern pattern = Pattern.compile(“\\d{5,}”);
Linkify.addLinks(mTv_kuaibao, pattern, “tel:”);
最后:防止点击事件冲突,在TextView的根部局中加入
android:descendantFocusability=”blocksDescendants”

3. 只自动识别电话

android:autoLink=”phone”

4. 只自动识别网址

android:autoLink=”web”

android postDelayed

这是一种可以创建多线程消息的函数
使用方法:
1. 首先创建一个Handler对象
Handler handler=new Handler();

2. 然后创建一个Runnable对象
Runnable runnable=new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
//要做的事情,这里再次调用此Runnable对象,以实现每两秒实现一次的定时器操作
handler.postDelayed(this, 2000);
}
};

3. 使用PostDelayed方法,两秒后调用此Runnable对象
handler.postDelayed(runnable, 2000);
实际上也就实现了一个2s的一个定时器

4. 如果想要关闭此定时器,可以这样操作
handler.removeCallbacks(runnable);

当然,你也可以做一个闹钟提醒延时的函数试试,比如,先用MediaPlayer播放闹钟声音,
如果不想起,被停止播放之后,下次就5分钟后再播放,再被停止的话,下次就4分钟后播放,
………………
只要更改延时的时间就可以实现了,用一个static对象的话会比较容易操作。

是可以异步效果,但Runnable的执行是在Handler对象所在的线程
如果其所在的线程是UI线程的话,Runnable中还是不能执行耗时操作,不然会ANR
前几天我们自己的设备很卡,卡到跳转界面都需要不到1秒的时间,我就把跳转的动作放在Runnable里边,外边加上弹出进度提示框

注:举例说明

public class XXX extends Activity

{
    @Override
    public void onCreate(Bundle savedInstanceState)

    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.loading); // 显示第1屏
        Handler handler = new Handler();
        handler.postDelayed(new splashhandler(), 2000); // 延迟2秒,再运行splashhandler的run()
    }

    class splashhandler implements Runnable

     {
        public void run()

       {
            startActivity(new Intent(getApplication(),  SecondActivity.class)); // 显示第2屏
            XXX.this.finish();   // 结束第1屏
        }
    }
}

Android setTextSize

在帮TextView控件设置大小的时候,发现和在XML中用PX设置的不一样,原因是setTextSize()默认的单位是sp,可以用另一个设置字体大小的方法:

setTextSize(int unit, int size)

第一个参数可设置如下静态变量:

TypedValue.COMPLEX_UNIT_PX : Pixels
TypedValue.COMPLEX_UNIT_SP : Scaled Pixels
TypedValue.COMPLEX_UNIT_DIP : Device Independent Pixels

Android安卓平台上网页WebView中全屏横屏播放html5视频的实现

可以实现在WebView中全屏横屏播放html5视频,但是没办法播放的时候直接进入全屏,因为监听不到播放事件。如果有兴趣可以考虑使用点击事件的监听来曲线救国。

继续阅读“Android安卓平台上网页WebView中全屏横屏播放html5视频的实现”

Android分享对话框实现,Android7.0之后状态栏着色解决——主题(Theme)的正确玩法

现象

根本原因是BaseActivity基类中,进行了状态栏着色,代码如下: 继续阅读“Android分享对话框实现,Android7.0之后状态栏着色解决——主题(Theme)的正确玩法”