前言:
最近需要写个app方便工作,第一次写app,这里做个记录,方便以后代码的粘贴复制。
首先编写activity_main.xml,其中添加了四个按钮,对应四个功能,分别为添加服务,关闭服务,发送邮件和提权:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><Buttonandroid:id="@+id/btn_start"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="调用startService()方法开启服务"/><Buttonandroid:id="@+id/btn_stop"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="关闭服务"/><Buttonandroid:id="@+id/btn_emain"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试邮件"/><Buttonandroid:id="@+id/btn_quanxian"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="提升权限"/></LinearLayout>
主界面MainActivity:
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.Provider;import javax.mail.MessagingException;public class MainActivity extends AppCompatActivity {public static Context mContext;@SuppressLint("ResourceType")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mContext = this;setContentView(R.xml.activity_main);inti();//调用init()方法}//inti()方法,在该方法中获取界面控件并实现控件的点击事件。private void inti() {Button btn_start = findViewById(R.id.btn_start);Button btn_stop = findViewById(R.id.btn_stop);Button btn_emain = findViewById(R.id.btn_emain);Button btn_quanxian = findViewById(R.id.btn_quanxian);btn_start.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//开启服务
// Intent intent = new Intent(MainActivity.this, MyService.class);
// startService(intent);Intent service = new Intent(getApplicationContext(), MyService.class);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startService(service);}}});btn_stop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//关闭服务Intent intent = new Intent(MainActivity.this, MyService.class);stopService(intent);}});btn_emain.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送邮件测试SendEmail sendEmail = new SendEmail();sendEmail.execute();}});btn_quanxian.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {// 在后台线程中执行获取root权限和执行shell命令的操作new Thread(new Runnable() {@Overridepublic void run() {executeShellCommandWithRoot();}}).start();}});}
}
创建服务:
添加服务,并创建服务内容为定时执行:
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;public class MyService extends Service {private static final String TAG = "Servicelog";private static final long INTERVAL_MS = 24 * 60 * 60 * 1000; // 每24小时执行一次任务private static final int MORNING_HOUR = 12;private static final int EVENING_HOUR = 20;private Handler handler;private Runnable runnable;//重写Service生命周期中的onCreate()方法@Overridepublic void onCreate(){super.onCreate();handler = new Handler();runnable = new Runnable() {@Overridepublic void run() {checkAndSendEmail();handler.postDelayed(this, INTERVAL_MS);}};}//重写Service生命周期中的onStartCommand()方法@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 获取当前时间Calendar calendar = Calendar.getInstance();int currentHour = calendar.get(Calendar.HOUR_OF_DAY);// 计算下一个执行任务的时间long delayMs;if (currentHour < MORNING_HOUR) {// 计算时间差calendar.set(Calendar.HOUR_OF_DAY, MORNING_HOUR);delayMs = calendar.getTimeInMillis() - System.currentTimeMillis();} else if (currentHour < EVENING_HOUR) {// 计算时间差calendar.set(Calendar.HOUR_OF_DAY, EVENING_HOUR);delayMs = calendar.getTimeInMillis() - System.currentTimeMillis();} else {// 计算时间差calendar.add(Calendar.DAY_OF_MONTH, 1);calendar.set(Calendar.HOUR_OF_DAY, MORNING_HOUR);delayMs = calendar.getTimeInMillis() - System.currentTimeMillis();}// 启动定时任务handler.postDelayed(runnable, delayMs);return START_STICKY;}@Overridepublic IBinder onBind(Intent intent) {return null;}//重写Service生命周期中的onStartCommand()方法@Overridepublic void onDestroy() {Log.i("Myservice","关闭服务,执行onDestroy()方法");super.onDestroy();}private void checkAndSendEmail() {//发送邮件测试SendEmail sendEmail = new SendEmail();sendEmail.execute();}private void createScreenCapture(){String command1 = "input keyevent 224\n";String command2 = "input swipe 300 1000 300 500\n";try {// 执行Shell命令// 执行su命令获取root权限Process suProcess = Runtime.getRuntime().exec("su");// 获取su进程的输出流DataOutputStream outputStream = new DataOutputStream(suProcess.getOutputStream());Log.d(TAG,command1);// 执行id命令获取用户身份信息outputStream.writeBytes(command1);outputStream.writeBytes(command2);outputStream.flush();// 关闭输出流outputStream.writeBytes("exit\n");outputStream.flush();outputStream.close();// 等待命令执行完成suProcess.waitFor();} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
发送邮件:
使用 QQ邮件发送邮件,并在邮件中添加图片:
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;public class SendEmail extends AsyncTask<Void, Void, Boolean>{private static final String SMTP_HOST = "smtp.qq.com";private static final int SMTP_PORT = 465;private static final String USERNAME = "qq@qq.com";private static final String PASSWORD = "password";private static final String SENDER_EMAIL = "qq@qq.com";private static final String RECIPIENT_EMAIL = "RECIPIENT@outlook.com";private static final String EMAIL_SUBJECT = "Test";private static final String EMAIL_BODY = "邮件正文";private static final String IMAGE_PATH = "/sdcard/Pictures/01.png";;@Overrideprotected void onPostExecute(Boolean success) {if (success) {SendEmail.show(MainActivity.mContext, "邮件发送成功");// 邮件发送成功的处理Log.d("MyTag", "邮件发送成功");} else {SendEmail.show(MainActivity.mContext, "邮件发送失败");// 邮件发送失败的处理Log.d("MyTag", "邮件发送失败");}}@Overrideprotected Boolean doInBackground(Void... voids) {try {Log.d("MyTag", "邮件发送。。。。。");Properties props = new Properties();props.put("mail.smtp.host", SMTP_HOST);props.put("mail.smtp.port", SMTP_PORT);props.put("mail.smtp.auth", "true");props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");Session session = Session.getInstance(props, new javax.mail.Authenticator() {protected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(USERNAME, PASSWORD);}});Message message = new MimeMessage(session);message.setFrom(new InternetAddress(SENDER_EMAIL));message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(RECIPIENT_EMAIL));message.setSubject(EMAIL_SUBJECT);// 创建邮件内容MimeMultipart content = new MimeMultipart();// 添加文本内容MimeBodyPart textPart = new MimeBodyPart();textPart.setText(EMAIL_BODY);content.addBodyPart(textPart);// 添加图片MimeBodyPart imagePart = new MimeBodyPart();Bitmap bitmap = BitmapFactory.decodeFile(IMAGE_PATH);ByteArrayOutputStream stream = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);byte[] byteArray = stream.toByteArray();ByteArrayDataSource dataSource = new ByteArrayDataSource(byteArray, "image/png");imagePart.setDataHandler(new javax.activation.DataHandler(dataSource));imagePart.setFileName("image.png");content.addBodyPart(imagePart);// 设置邮件内容message.setContent(content);Transport.send(message);return true;} catch (MessagingException e) {e.printStackTrace();return false;}}private static final int DEFAULT_DURATION = Toast.LENGTH_SHORT;public static void show(Context context, String message) {show(context, message, DEFAULT_DURATION);}public static void show(Context context, String message, int duration) {final Toast toast = Toast.makeText(context, message, duration);// 显示Toasttoast.show();// 延迟一段时间后自动取消ToastHandler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {toast.cancel();}}, duration == Toast.LENGTH_LONG ? 3500 : 2000); // 使用不同的延迟时间来适应不同的Toast持续时间}
}
提升权限代码:
使用shell命令提升权限,需要有root权限:
private void executeShellCommandWithRoot() {try {Process process = Runtime.getRuntime().exec("su");DataOutputStream outputStream = new DataOutputStream(process.getOutputStream());// 在这里执行需要root权限的shell命令// 例如,执行 "ls" 命令outputStream.writeBytes("id\n");outputStream.flush();// 读取命令执行的结果BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));StringBuilder output = new StringBuilder();output.append(reader.readLine()).append("\n");// 输出结果String outputStr = output.toString();Log.d("Root", "Output: " + outputStr);// 关闭流outputStream.writeBytes("exit\n");outputStream.flush();outputStream.close();process.waitFor();} catch (IOException | InterruptedException e) {e.printStackTrace();}}
最后AndroidManifest.xml中添加权限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.MyTest"android:requestLegacyExternalStorage="true"tools:targetApi="31"><activityandroid:name=".MainActivity"android:exported="true"tools:ignore="WrongManifestParent"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><serviceandroid:name=".MyService"android:foregroundServiceType="mediaProjection"android:enabled="true"android:exported="true"tools:ignore="ForegroundServicePermission"></service></application><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/></manifest>
上述代码实现了发送邮件和创建服务,并执行定时任务,但是由于android回收机制,一段时间后服务就会被kill,不能长久在后台运行,需要注意。