编译环境(Windows)
下载代码后,需要下载特定版本的NDK15c, 并在Android Studio中配置NDK路径。其他的根据Gradle的sync提示来就行。
Gradle
implementation 和 api
implementation会把类添加到编译并打包到输出。
gradle的dependencies中的compile已过时,用implementation或api代替。区别在于api会把引用的接口传到给上层的其他库,如果你在编译一个库并且需要暴露接口时用这个,一般用implementation
随着应用的范围不断扩大,它可能会包含许多依赖项,包括直接依赖项和传递依赖项(应用中导入的库所依赖的库)。要排除不再需要的传递依赖项,您可以使用 exclude 关键字
dependencies {
implementation('some-library') {
exclude group: 'com.example.imgtools', module: 'native'
}
}
compileOnly
这个选项只会把依赖添加到编译路径,但是不打包。替换旧的provided.
最好在运行时检查一下。
runtimeOnly
只会把依赖添加到输出,不会添加到编译类路径。
以上配置会将依赖项应用于所有编译变体。如果您只想为特定的编译变体源集或测试源集声明依赖项,则必须将配置名称的首字母大写,并在其前面加上编译变体或测试源集的名称作为前缀。
例如,要将 implementation
依赖项仅添加到“free”产品特性(使用远程二进制文件依赖项),请使用如下所示的代码:
dependencies {
freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
}
不过,如果您想为将产品特性和版本类型组合在一起的变体添加依赖项,则必须在 configurations
代码块中初始化配置名称。以下示例将 runtimeOnly
依赖项添加到“freeDebug”编译变体(使用本地二进制文件依赖项):
configurations {
// Initializes a placeholder for the freeDebugRuntimeOnly
// dependency configuration.
freeDebugRuntimeOnly {}
}
dependencies {
freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
}
修改ndk架构
为x86平台的设备发布solopi时,把shared模块下android->defaultConfig的ndk修改为支持x86
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64', 'x86'
}
命令行编译Gradle
参考:https://developer.android.com/studio/build/building-cmdline
gradle wrapper
当在Studio中设置为使用缺省的Gradle Wrapper
之后,它会调用
编译依赖
从github文档中提及的编译依赖:
- macOS 10.14.3
- Android Studio 3.2
- Gradle 4.4(Android Studio打开项目时会提示升级Gradle版本,建议不要进行升级)
- CMake 3.6..4111459(建议不要进行升级)
- Ndk 15.2.4203819
- TargetApi 25
- MinimumApi 18
- 注意,构建时请将Android Studio的instant run功能关闭,否则打出来的安装包会无法使用
设置悬浮窗
浮动在其他应用上面的悬浮窗。在Service中,用WindowManager来往里面写入,需要SYSTEM_ALERT_WINDOW权限。
参考:https://blog.csdn.net/dongzhong1990/article/details/80512706
悬浮窗权限
在某些设备上,阉割掉了设置菜单里面的悬浮窗口权限设置这块。可以使用 adb shell pm grant com.alipay.hulu android.permission.SYSTEM_ALERT_WINDOW 来手动设置权限,设置之后权限检查可以通过。
Notification 和 start-foreground-service
在新版本的android中,如果用adb shell am startservice来启动service会报错。提示需要调用 start-foreground-service
那么当服务启动后,我们需要调用 startForeground(NOTIFICATION_ID, notification) 来让它保持在前台
那么我们还需要建立一个Notification,而在新版本的Android中(似乎是安卓O以上),需要新建一个NotificationChannel。
悬浮窗体的示例代码:
package com.zzp.floating;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.Button;
public class FloatingService extends Service {
private static final String TAG = "ZZP_Floating";
private static final int NOTIFICATION_ID = 1313;
private static final String CHANNEL_ID = "floating_channel";
private WindowManager windowManager;
private WindowManager.LayoutParams layoutParams;
InterceptService service;
private Button button;
@Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
layoutParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.width = 500;
layoutParams.height = 100;
layoutParams.x = 300;
layoutParams.y = 300;
createNotificationChannel();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int type = intent.getIntExtra("type", -1);
switch (type) {
case 1:
Log.d(TAG, "onStartCommand: floating");
showFloatingWindow();
break;
case 2:
Log.d(TAG, "onStartCommand: intercept");
InterceptService.getInstance().setBlock();
break;
case 3:
Log.d(TAG, "onStartCommand: stop intercept");
InterceptService.getInstance().setNormal();
break;
case 4:
Intent intent1 = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
break;
default:
break;
}
Notification.Builder builder = new Notification.Builder(this)
.setContentText(getString(R.string.float__toast_title))
.setCategory(Notification.CATEGORY_SERVICE)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_foreground);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O){
builder.setChannelId(CHANNEL_ID);
}
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
return super.onStartCommand(intent, flags, startId);
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void showFloatingWindow() {
if (Settings.canDrawOverlays(this)) {
button = new Button(getApplicationContext());
button.setText("Floating Window");
button.setBackgroundColor(Color.BLUE);
windowManager.addView(button, layoutParams);
}
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
转载请注明出处。
image更多视频教程请在网易云课堂搜索黑山老雕。
网友评论