Преглед изворни кода

1.添加glide框架

2.添加FileUtils
3.添加壁纸请求接口
20241218TB223FC(测试jar包)
wangwanlei пре 8 месеци
родитељ
комит
998a7c67d2

+ 9
- 0
app/src/main/java/com/xhly/manageapp/bean/WallpaperBean.kt Прегледај датотеку

@@ -0,0 +1,9 @@
1
+package com.xhly.manageapp.bean
2
+
3
+class WallpaperBean {
4
+    //横屏壁纸
5
+    var hPath: String? = null
6
+
7
+    //竖屏壁纸
8
+    var vpath: String? = null
9
+}

+ 5
- 0
app/src/main/java/com/xhly/manageapp/network/UriAdress.kt Прегледај датотеку

@@ -60,4 +60,9 @@ object UriAdress {
60 60
      * 设备设置管理
61 61
      */
62 62
     const val DEVICESETDETAIL = "/schoolSet/detail"
63
+
64
+    /**
65
+     * 获得壁纸
66
+     */
67
+    const val WALLPAPERPAD="/wallpaper/detail_pad"
63 68
 }

+ 11
- 1
app/src/main/java/com/xhly/manageapp/network/app/AppService.kt Прегледај датотеку

@@ -4,17 +4,21 @@ import com.xhly.corelib.network.bean.ResponseData
4 4
 import com.xhly.manageapp.bean.AppModel
5 5
 import com.xhly.manageapp.bean.ListAppBean
6 6
 import com.xhly.manageapp.bean.UpdateBean
7
+import com.xhly.manageapp.bean.WallpaperBean
7 8
 import com.xhly.manageapp.network.UriAdress
8 9
 import retrofit2.http.Body
9 10
 import retrofit2.http.POST
10 11
 
11 12
 interface AppService {
12 13
     /**
13
-     * 获得应用列表包含必装应用和推荐
14
+     * 获得应用列表包含必装应用和推荐,这些应用即为显示白名单。
14 15
      */
15 16
     @POST(UriAdress.LIST_APP)
16 17
     suspend fun postListApp(@Body listapp: ListAppBean): ResponseData<ArrayList<AppModel>>
17 18
 
19
+    /**
20
+     * 获得必装应用
21
+     */
18 22
     @POST(UriAdress.FORCEAPP)
19 23
     suspend fun postForceApp(): ResponseData<ArrayList<AppModel>>
20 24
 
@@ -23,4 +27,10 @@ interface AppService {
23 27
      */
24 28
     @POST(UriAdress.CLIENT_ADD)
25 29
     suspend fun postClientAdd(@Body updateBean: UpdateBean): ResponseData<Any>
30
+
31
+    /**
32
+     * 获得设备壁纸。
33
+     */
34
+    @POST(UriAdress.WALLPAPERPAD)
35
+    suspend fun postWallpaperPad(): ResponseData<WallpaperBean>
26 36
 }

+ 37
- 2
app/src/main/java/com/xhly/manageapp/ui/main/activity/MainActivity.kt Прегледај датотеку

@@ -9,10 +9,12 @@ import android.content.Intent
9 9
 import android.content.IntentFilter
10 10
 import android.content.pm.PackageManager
11 11
 import android.graphics.Color
12
+import android.graphics.drawable.Drawable
12 13
 import android.provider.Settings
13 14
 import android.view.View
14 15
 import android.widget.Button
15 16
 import android.widget.EditText
17
+import android.widget.LinearLayout
16 18
 import android.widget.TextView
17 19
 import android.widget.Toast
18 20
 import androidx.activity.addCallback
@@ -20,6 +22,9 @@ import androidx.lifecycle.viewModelScope
20 22
 import androidx.recyclerview.widget.GridLayoutManager
21 23
 import androidx.work.PeriodicWorkRequest
22 24
 import androidx.work.WorkManager
25
+import com.bumptech.glide.Glide
26
+import com.bumptech.glide.request.target.CustomViewTarget
27
+import com.bumptech.glide.request.transition.Transition
23 28
 import com.kongzue.dialogx.dialogs.CustomDialog
24 29
 import com.kongzue.dialogx.interfaces.OnBindView
25 30
 import com.tbruyelle.rxpermissions2.RxPermissions
@@ -28,6 +33,7 @@ import com.xhly.corelib.bean.AppInfo
28 33
 import com.xhly.corelib.eventbus.UIEvent
29 34
 import com.xhly.corelib.utils.AppUtils
30 35
 import com.xhly.corelib.utils.CustomOSUtils
36
+import com.xhly.corelib.utils.FileUtils
31 37
 import com.xhly.corelib.utils.GsonUtils
32 38
 import com.xhly.corelib.utils.LogShow
33 39
 import com.xhly.corelib.utils.SharedPreferencesUtils
@@ -91,7 +97,7 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
91 97
          val permissionIntent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
92 98
           startActivity(permissionIntent)*/
93 99
         // csdkManagerUtils.csdkManager.enableAccessibility("com.xhly.manageapp","com.xhly.manageapp.service.TestService",true)
94
-        viewModel.getAppList()
100
+
95 101
         viewModel.listAppData.observe(this) { modelList ->
96 102
             //获得应用集合,必装应用和推荐应用,再加上预装应用,其余应用需要静默卸载,必装应用需要进行静默下载和安装。安装应用从forceapp接口获取
97 103
             val appList = AppUtils.GetAppList(this)
@@ -102,8 +108,11 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
102 108
             }
103 109
         }
104 110
         viewModel.forceListAppData.observe(this) { modelList ->
105
-            //获得必装应用,未安装或者版本较低则更新
111
+            //获得必装应用,未安装或者版本较低则更新,先删除目录中的文件
106 112
             val appList = AppUtils.GetAppList(this)
113
+            getExternalFilesDir(null)?.let {
114
+                FileUtils.deleteCurrentFlie(it)
115
+            }
107 116
             modelList.forEach { app ->
108 117
                 //获得已安装的应用判断版本,未安装的则直接静默安装。
109 118
                 val filter = appList.filter { it.packageName.equals(app.appPackage) }
@@ -158,6 +167,30 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
158 167
             initSchoolSet(it)
159 168
             updateAppRv()
160 169
         }
170
+        viewModel.wallpaperData.observe(this){
171
+            if (!it.hPath.isNullOrBlank()){
172
+                Glide.with(this).load(Const.URL1+it.hPath).placeholder(R.drawable.main_bg).error(R.drawable.main_bg).into(object:CustomViewTarget<LinearLayout,Drawable>(mBinding.root){
173
+                    override fun onLoadFailed(errorDrawable: Drawable?) {
174
+                        errorDrawable?.let {drawble->
175
+                            mBinding.root.background=drawble
176
+                        }
177
+                    }
178
+
179
+                    override fun onResourceCleared(placeholder: Drawable?) {
180
+                        placeholder?.let {drawble->
181
+                            mBinding.root.background=drawble
182
+                        }
183
+                    }
184
+
185
+                    override fun onResourceReady(
186
+                        resource: Drawable,
187
+                        transition: Transition<in Drawable>?
188
+                    ) {
189
+                        mBinding.root.background=resource
190
+                    }
191
+                })
192
+            }
193
+        }
161 194
         startWorkManager()
162 195
     }
163 196
 
@@ -195,8 +228,10 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
195 228
 
196 229
     override fun onResume() {
197 230
         super.onResume()
231
+        viewModel.postWallpaperPad()
198 232
         viewModel.updateStrategy()
199 233
         viewModel.uploadAppStrategy()
234
+        viewModel.getAppList()
200 235
         userBean?.let {
201 236
             viewModel.postDevicesetDetail(it.schoolid)
202 237
         }

+ 16
- 0
app/src/main/java/com/xhly/manageapp/ui/main/viewmodel/MainViewModel.kt Прегледај датотеку

@@ -7,6 +7,7 @@ import com.xhly.corelib.network.RetrofitService
7 7
 import com.xhly.manageapp.bean.AppModel
8 8
 import com.xhly.manageapp.bean.ListAppBean
9 9
 import com.xhly.manageapp.bean.UpdateBean
10
+import com.xhly.manageapp.bean.WallpaperBean
10 11
 import com.xhly.manageapp.bean.log.LogdOperateBean
11 12
 import com.xhly.manageapp.bean.log.PadInfoBean
12 13
 import com.xhly.manageapp.bean.school.SchoolDeviceSetBean
@@ -40,6 +41,9 @@ class MainViewModel : CommonBaseViewModel() {
40 41
     private val schoolSet=MutableLiveData<SchoolDeviceSetBean>()
41 42
     val schoolSetData:LiveData<SchoolDeviceSetBean> =schoolSet
42 43
 
44
+    private val wallpaper=MutableLiveData<WallpaperBean>()
45
+    val wallpaperData:LiveData<WallpaperBean> =wallpaper
46
+
43 47
     fun getAppList() {
44 48
         launchUI {
45 49
             val postListApp = appService.postListApp(ListAppBean())
@@ -158,4 +162,16 @@ class MainViewModel : CommonBaseViewModel() {
158 162
             }
159 163
         }
160 164
     }
165
+
166
+    /**
167
+     * 获得壁纸
168
+     */
169
+    fun postWallpaperPad(){
170
+        launchUI {
171
+            val postWallpaperPad = appService.postWallpaperPad()
172
+            if (postWallpaperPad.code==0){
173
+                wallpaper.value=postWallpaperPad.obj
174
+            }
175
+        }
176
+    }
161 177
 }

+ 2
- 0
corelib/build.gradle.kts Прегледај датотеку

@@ -64,6 +64,8 @@ dependencies {
64 64
     api(libs.com.squareup.retrofit2.converter.scalars)
65 65
     api(libs.com.squareup.okhttp3.logging.interceptor)
66 66
     api(libs.com.jakewharton.retrofit.retrofit2.kotlin.coroutines.adapter2)
67
+    //glide
68
+    api(libs.bumptech.glide)
67 69
 
68 70
     //rxjava
69 71
     api(libs.rxjava)

+ 397
- 0
corelib/src/main/java/com/xhly/corelib/utils/FileUtils.java Прегледај датотеку

@@ -0,0 +1,397 @@
1
+package com.xhly.corelib.utils;
2
+
3
+import android.content.Context;
4
+import android.os.Handler;
5
+import android.os.Looper;
6
+import android.os.Message;
7
+import android.util.Log;
8
+
9
+import java.io.BufferedReader;
10
+import java.io.ByteArrayOutputStream;
11
+import java.io.File;
12
+import java.io.FileInputStream;
13
+import java.io.FileOutputStream;
14
+import java.io.IOException;
15
+import java.io.InputStream;
16
+import java.io.InputStreamReader;
17
+import java.io.OutputStream;
18
+import java.util.Arrays;
19
+import java.util.Comparator;
20
+
21
+/**
22
+ * Created by YQ015 on 2018/4/12.
23
+ */
24
+
25
+public class FileUtils {
26
+
27
+    private static FileUtils instance;
28
+    private static final int SUCCESS = 1;
29
+    private static final int FAILED = 0;
30
+    private Context context;
31
+    private FileOperateCallback callback;
32
+    private volatile boolean isSuccess;
33
+    private String errorStr;
34
+
35
+    public static FileUtils getInstance(Context context) {
36
+        if (instance == null)
37
+            instance = new FileUtils(context);
38
+        return instance;
39
+    }
40
+
41
+    public static FileUtils getInstance() {
42
+        if (instance == null)
43
+            instance = new FileUtils();
44
+        return instance;
45
+    }
46
+
47
+    private FileUtils() {
48
+    }
49
+
50
+    private FileUtils(Context context) {
51
+        this.context = context;
52
+    }
53
+
54
+    private Handler handler = new Handler(Looper.getMainLooper()) {
55
+        @Override
56
+        public void handleMessage(Message msg) {
57
+            super.handleMessage(msg);
58
+            if (callback != null) {
59
+                if (msg.what == SUCCESS) {
60
+                    callback.onSuccess();
61
+                }
62
+                if (msg.what == FAILED) {
63
+                    callback.onFailed(msg.obj.toString());
64
+                }
65
+            }
66
+        }
67
+    };
68
+
69
+
70
+    public static void moveFile(String fromFile, String toFile) {
71
+        //安卓9.0多出两个缓存文件wal和shm
72
+        File fromfile = new File(fromFile);
73
+        File tofile = new File(toFile);
74
+        if (!tofile.exists()) {
75
+            try {
76
+                if (tofile.isDirectory()) {
77
+                    tofile.mkdir();
78
+                } else {
79
+                    tofile.createNewFile();
80
+                }
81
+            } catch (IOException e) {
82
+                e.printStackTrace();
83
+            }
84
+        }
85
+        CopyFile(fromfile.toString(), tofile.toString());
86
+        if (fromfile.exists()) {
87
+            fromfile.delete();
88
+        }
89
+    }
90
+
91
+    public FileUtils copyAssetsToSD(final String srcPath, final String sdPath) {
92
+        new Thread(new Runnable() {
93
+            @Override
94
+            public void run() {
95
+                copyAssetsToDst(context, srcPath, sdPath);
96
+                Log.d(this.getClass().getName(),"失败没有="+isSuccess);
97
+                if (isSuccess)
98
+                    handler.obtainMessage(SUCCESS).sendToTarget();
99
+                else
100
+                    handler.obtainMessage(FAILED, errorStr).sendToTarget();
101
+            }
102
+        }).start();
103
+        return this;
104
+    }
105
+
106
+    public static void CopyDir(String sourcePath, String newPath) throws IOException {
107
+        File file = new File(sourcePath);
108
+        String[] filePath = file.list();
109
+
110
+        if (!(new File(newPath)).exists()) {
111
+            (new File(newPath)).mkdir();
112
+        }
113
+
114
+        for (int i = 0; i < filePath.length; i++) {
115
+            if ((new File(sourcePath + file.separator + filePath[i])).isDirectory()) {
116
+                CopyDir(sourcePath + file.separator + filePath[i], newPath + file.separator + filePath[i]);
117
+            }
118
+
119
+            if (new File(sourcePath + file.separator + filePath[i]).isFile()) {
120
+                CopyFile(sourcePath + file.separator + filePath[i], newPath + file.separator + filePath[i]);
121
+            }
122
+
123
+        }
124
+    }
125
+
126
+    public static int CopyFile(String fromFile, String toFile) {
127
+        try {
128
+            InputStream fosfrom = new FileInputStream(fromFile);
129
+            OutputStream fosto = new FileOutputStream(toFile);
130
+            byte bt[] = new byte[1024];
131
+            int c;
132
+            while ((c = fosfrom.read(bt)) > 0) {
133
+                fosto.write(bt, 0, c);
134
+            }
135
+            fosfrom.close();
136
+            fosto.close();
137
+            return 0;
138
+
139
+        } catch (Exception ex) {
140
+            return -1;
141
+        }
142
+    }
143
+
144
+    public static int saveInputStreamFile(InputStream fosfrom, String toFile) {
145
+        try {
146
+            OutputStream fosto = new FileOutputStream(toFile);
147
+            byte bt[] = new byte[1024];
148
+            int c;
149
+            while ((c = fosfrom.read(bt)) > 0) {
150
+                fosto.write(bt, 0, c);
151
+            }
152
+            fosfrom.close();
153
+            fosto.close();
154
+            return 0;
155
+
156
+        } catch (Exception ex) {
157
+            return -1;
158
+        }
159
+    }
160
+
161
+    /**
162
+     * 删除目录下的文件,不涉及下一级目录,不删除目录本身
163
+     * @param file 目录
164
+     * @return 0成功
165
+     */
166
+    public static int deleteCurrentFlie(File file) {
167
+        try {
168
+            if (file.isDirectory()) {
169
+                File[] files = file.listFiles();
170
+                for (int i = 0; i < files.length; i++) {
171
+                    files[i].delete();
172
+                }
173
+            }
174
+            return 0;
175
+        } catch (Exception ex) {
176
+            return -1;
177
+        }
178
+    }
179
+
180
+    //删除目录下的文件,只保留最新1条,不涉及下一级目录,不删除目录本身
181
+    public static int deleteOnlyOneFlie(File file) {
182
+        try {
183
+            if (file.isDirectory()) {
184
+                File[] files = file.listFiles();
185
+                // 根据文件的最后修改时间进行排序
186
+                Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
187
+                // 保留最新文件的数量
188
+                int keepCount = 1;
189
+                for (int i = keepCount; i < files.length; i++) {
190
+                    files[i].delete();
191
+                }
192
+            }
193
+            return 0;
194
+        } catch (Exception ex) {
195
+            return -1;
196
+        }
197
+    }
198
+
199
+    public static boolean deleteFile(String fileName) {
200
+        File file = new File(fileName);
201
+        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
202
+        if (file.exists() && file.isFile()) {
203
+            if (file.delete()) {
204
+                return true;
205
+            } else {
206
+                return false;
207
+            }
208
+        } else {
209
+            return false;
210
+        }
211
+    }
212
+
213
+    /**
214
+     * 删除目录及目录下的文件
215
+     *
216
+     * @param dir 要删除的目录的文件路径
217
+     * @return 目录删除成功返回true,否则返回false
218
+     */
219
+    public static boolean deleteDirectory(String dir) {
220
+        // 如果dir不以文件分隔符结尾,自动添加文件分隔符
221
+        if (!dir.endsWith(File.separator))
222
+            dir = dir + File.separator;
223
+        File dirFile = new File(dir);
224
+        // 如果dir对应的文件不存在,或者不是一个目录,则退出
225
+        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
226
+            return false;
227
+        }
228
+        boolean flag = true;
229
+        // 删除文件夹中的所有文件包括子目录
230
+        File[] files = dirFile.listFiles();
231
+        for (int i = 0; i < files.length; i++) {
232
+            // 删除子文件
233
+            if (files[i].isFile()) {
234
+                flag = FileUtils.deleteFile(files[i].getAbsolutePath());
235
+                if (!flag)
236
+                    break;
237
+            }
238
+            // 删除子目录
239
+            else if (files[i].isDirectory()) {
240
+                flag = FileUtils.deleteDirectory(files[i]
241
+                        .getAbsolutePath());
242
+                if (!flag)
243
+                    break;
244
+            }
245
+        }
246
+        if (!flag) {
247
+            return false;
248
+        }
249
+        // 删除当前目录
250
+        if (dirFile.toString().equals(dir.toString())) {
251
+            return true;
252
+        } else {
253
+            if (dirFile.delete()) {
254
+                return true;
255
+            } else {
256
+                return false;
257
+            }
258
+        }
259
+    }
260
+
261
+    public void setFileOperateCallback(FileOperateCallback callback) {
262
+        this.callback = callback;
263
+    }
264
+
265
+    private void copyAssetsToDst(Context context, String srcPath, String dstPath) {
266
+        try {
267
+            File outFile = new File(dstPath);
268
+            if (!outFile.exists()) {
269
+                outFile.createNewFile();
270
+                InputStream is = context.getAssets().open(srcPath);
271
+                FileOutputStream fos = new FileOutputStream(outFile);
272
+                byte[] buffer = new byte[1024];
273
+                int byteCount;
274
+                while ((byteCount = is.read(buffer)) != -1) {
275
+                    fos.write(buffer, 0, byteCount);
276
+                }
277
+                fos.flush();
278
+                is.close();
279
+                fos.close();
280
+            }
281
+            isSuccess = true;
282
+        } catch (Exception e) {
283
+            e.printStackTrace();
284
+            errorStr = e.getMessage();
285
+            isSuccess = false;
286
+            Log.d(this.getClass().getName(),"失败"+e.toString());
287
+        }
288
+    }
289
+
290
+    public byte[] getAssetsRes(Context context, String srcPath) {
291
+        try {
292
+            InputStream is = context.getAssets().open(srcPath);
293
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
294
+            byte[] buffer = new byte[4096];
295
+            int n = 0;
296
+            while (-1 != (n = is.read(buffer))) {
297
+                output.write(buffer, 0, n);
298
+            }
299
+            byte[] bytes = output.toByteArray();
300
+            return bytes;
301
+        } catch (IOException e) {
302
+            e.printStackTrace();
303
+        }
304
+        return null;
305
+    }
306
+
307
+
308
+    public String getAssetsResource(Context context, String srcPath) {
309
+        try {
310
+            InputStream is = context.getAssets().open(srcPath);
311
+            InputStreamReader inputStreamReader = null;
312
+            inputStreamReader = new InputStreamReader(is, "UTF-8");
313
+            BufferedReader reader = new BufferedReader(inputStreamReader);
314
+            StringBuffer sb = new StringBuffer("");
315
+            String line;
316
+            while ((line = reader.readLine()) != null) {
317
+                //添加到字符缓冲流中
318
+                sb.append(line);
319
+                sb.append("\n");
320
+            }
321
+            return sb.toString();
322
+        } catch (IOException e) {
323
+            e.printStackTrace();
324
+        }
325
+        return null;
326
+    }
327
+
328
+
329
+    public void writeFileData(String filename, String content, Context context) {
330
+        //写入文件到File目录下
331
+        try {
332
+            FileOutputStream fos = context.openFileOutput(filename, context.MODE_PRIVATE);//获得FileOutputStream
333
+            //将要写入的字符串转换为byte数组
334
+            byte[] bytes = content.getBytes();
335
+            fos.write(bytes);//将byte数组写入文件
336
+            fos.close();//关闭文件输出流
337
+
338
+        } catch (Exception e) {
339
+            e.printStackTrace();
340
+        }
341
+    }
342
+
343
+    public void writeFileToPath(String filename, String content) {
344
+        //写入文件到自定义目录下
345
+        try {
346
+            FileOutputStream fos = new FileOutputStream(filename);
347
+            //将要写入的字符串转换为byte数组
348
+            byte[] bytes = content.getBytes();
349
+            fos.write(bytes);//将byte数组写入文件
350
+            fos.close();//关闭文件输出流
351
+
352
+        } catch (Exception e) {
353
+            e.printStackTrace();
354
+        }
355
+    }
356
+
357
+    public void writeFileToPath(String filename, byte[] bytes) {
358
+        //写入文件到自定义目录下
359
+        try {
360
+            FileOutputStream fos = new FileOutputStream(filename);
361
+            //将要写入的字符串转换为byte数组
362
+            fos.write(bytes);//将byte数组写入文件
363
+            fos.close();//关闭文件输出流
364
+
365
+        } catch (Exception e) {
366
+            e.printStackTrace();
367
+        }
368
+    }
369
+
370
+    public String readFileToPath(String filename) {
371
+        //读取自定义目录下文件
372
+        try {
373
+            FileInputStream is = new FileInputStream(filename);
374
+            InputStreamReader inputStreamReader = null;
375
+            inputStreamReader = new InputStreamReader(is, "UTF-8");
376
+            BufferedReader reader = new BufferedReader(inputStreamReader);
377
+            StringBuffer sb = new StringBuffer("");
378
+            String line;
379
+            while ((line = reader.readLine()) != null) {
380
+                //添加到字符缓冲流中
381
+                sb.append(line);
382
+                sb.append("\n");
383
+            }
384
+            return sb.toString();
385
+        } catch (IOException e) {
386
+            e.printStackTrace();
387
+        }
388
+        return null;
389
+    }
390
+
391
+
392
+    public interface FileOperateCallback {
393
+        void onSuccess();
394
+
395
+        void onFailed(String error);
396
+    }
397
+}

+ 2
- 0
gradle/libs.versions.toml Прегледај датотеку

@@ -35,6 +35,7 @@ gittoaster = "12.3"
35 35
 adapterhelper = "3.0.4"
36 36
 cardview = "1.0.0"
37 37
 work-runtime-ktx = "2.9.0"
38
+glide-version="4.15.1"
38 39
 
39 40
 [libraries]
40 41
 
@@ -91,6 +92,7 @@ androidx-cardview = { group = "androidx.cardview", name = "cardview", version.re
91 92
 
92 93
 jessyanandroidautosize = { module = "com.github.JessYanCoding:AndroidAutoSize", version.ref = "androidautosize" }
93 94
 androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work-runtime-ktx" }
95
+bumptech-glide={module="com.github.bumptech.glide:glide",version.ref="glide-version"}
94 96
 
95 97
 [plugins]
96 98
 androidApplication = { id = "com.android.application", version.ref = "agp" }

Loading…
Откажи
Сачувај