2 软件开发
在进行Android程序的开发之前,需要先配置好IDE。一个好的IDE可以极大地提高Android程序的开发效率。

2.1 Java环境搭建、版本选择、安装以及PATH设置

2.1.1 Window安装Java需要的工具

JDK: JDK是Java语言的软件开发工具包,它包含了Java的运行环境、工具集合、基础类库等内容。
Android SDK:Android SDK是谷歌提供的Android开发工具包。在开发Android程序时,我们需要引入该工具包,来使用Android相关的API。
Android Studio:Android Studio是谷歌推出一款官方的IDE工具,由于不再是以插件的形式存在,Android Studio 在开发Android程序时远比Eclipse强大和方便的多。

2.1.2 下载JDK

首先需要下载Java开发工具包JDK,下载地址如下:
点击下图中红圈所示的下载按钮:
在下载页面中选择接受许可,并根据自己的系统选择对应的版本,我们以 Windows 64位系统为例:
下载后JDK的安装根据提示进行。安装JDK的同时也会自动安装JRE,可以一并安装。安装过程中可以自定义安装目录等信息,例如我们选择安装目录为 C:\Program Files (x86)\Java\jdk1.8.0_91。

2.1.3 配置环境变量

1.安装完成后,右击“我的电脑”,点击“属性”,选择“高级系统设置”;
2.选择“高级”选项卡,点击“环境变量”;
3.在“系统变量”中设置3项属性,”JAVA_HOME”, “PATH”, “CLASSPATH”(不限制大小写),若已存在则点击“编辑”,不存在则点击“新建”。
变量设置参数如下:
变量名
变量值
JAVA_HOME
C:\Program Files (x86)\Java\jdk1.8.0_91 //根据自己的实际路径配置
PATH
%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
CLASSPATH
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; //注意前面有个"."
注意:此处配置完成后PATH需要重新配置为%JAVA_HOME%\bin;,否则命令行和Eclipse等相关操作将无法正常使用。
JAVA_HOME 设置
PATH设置
CLASSPATH 设置
这是 Java 的环境配置,配置完成后,启动 Eclipse 来编写代码,它会自动完成java环境的配置。

2.1.4 测试JDK是否安装成功

1.“开始”->“运行”,键入“cmd”;
2.键入命令: java-version、java、javac 几个命令,出现以下信息,说明环境变量配置成功:

2.2 Android Studio版本、安装及环境搭建

2.2.1下载并安装android-studio

进入下载地址http://www.android-studio.org/,在页面点击下载Android Studio。
1.双击下载下来的安装包,双击安装包进行安装,然后点击“Next”,如下图所示:
2.勾选Android Virtual Device,然后点击“Next”,如下图所示:
3.点击“I Agree”按钮,如下图所示:
4. 选择Android Studio安装位置和Android SDK安装位置,然后点击“Next”,如下图所示:
5.点击“Install”按钮,如下图所示:
6.安装过程如下图所示:
7.直至安装完成,如下图所示:
8.此时最好使用翻墙工具,可以访问到google,确保可以下载相应的文件,如下图所示:
9.下载完成,点击”Finish”,如下图所示:
10.如果需要继续安装其他版本SDK,打开Android Studio,点击Configure,如下图所示:
11.选择SDK Manager,如下图所示:
12.在打开的Default Settings中,点击”Launch Standalone SDK Manager“,如下图所示:
13.在打开了的SDK Manager框下面,可以选择对应的SDK,然后翻墙进行下载,如下图所示:

2.2.2 用Android Studio配置NDK开发环境

Android Studio没有像Eclipse那样的一键add native support,相对来说比较麻烦。下面介绍在Android Studio中如何实现类似于Eclipse的add native support功能(即进行NDK开发的步骤)。
第一步:安装NDK
打开Tools->Android->SDK Manager->SDK Tools选中”LLDB”和”NDK”,点击确认,软件会自动安装NDK。
第二步:将so库导入libs目录下(project结构)
第三步:同步资源库

2.2.3 Android Assistant下载

2.3串口开发、demo简介、源代码提供连接

2.3.1 串口通信

串口通信(Serial Communications),是指外设和计算机间通过数据信号线、地线、控制线等,按位进行传输数据的一种通讯方式。串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于进行通信的端口,这些参数必须匹配。

2.3.2 安卓屏和安卓程序间的串口通讯的实现

实现步骤:
1.串口初始化——创建串口实例、设置串口参数(定义路径和波特率);
2.获取输入流——读取串口数据;
3.获取输出流——向串口发送数据;
4.数据处理与显示;
5.关闭串口。

2.3.3 串口Demo代码说明

第一步:导入SO
1. 拷贝相应架构下的so到项目的jinLibs文件夹
2.在build.gradle的android标签下添加配置
1
sourceSets {
2
main {
3
jni.srcDirs = []
4
jniLibs.srcDirs = ['src/main/jniLibs', 'libs']
5
}
6
}
Copied!
第二步:拷贝的android_sericalport_api包下的所有文件到自己项目的java文件夹下,注意路径不能换
第三步:使用串口
1. 初始化操作SerialPortManager
1
SerialPortManager.getInstances().initSerialPort();
Copied!
2 . 打开串口
// 获取串口工具类对象实例(该实例用于打开关闭串口和发送数据等)
1
SerialPortserialPort = SerialPortManager.getInstances().getSerialPort();
Copied!
// 初始化读监听器
1
ReadListenerreadListener= new ReadListener() {
2
@Override
3
public void onRead(final String port, final booleanisAscii, final String read) {
4
Log.d("SerialPortRead", new StringBuffer()
5
.append("串口号:").append(port)
6
.append("\n数据格式:").append(isAscii ? "ascii" :"hexString")
7
.append("\nread:").append(read).toString());
8
}
9
};
Copied!
// 用串口工具类对象实例打开串口传入读监听
1
serialPort.startSerialPort(SerialPortManager.ttyCOM0, false, readListener);// 打开串口/dev/ttyCOM0,读数据格式是HexString。
Copied!
3.修改读数据格式
1
serialPort.setReadCode(SerialPortManager.ttyCOM0, true);// 修改串口/dev/ttyCOM0读数据格式为Ascii
Copied!
4.发送数据(需先打开串口)
1
serialPort.writeSerialService(SerialPortManager.ttyCOM0, false, "我是要发送的数据");// 向串口/dev/ttyCOM0写数据,数据格式为HexString,数据内容为:"我是要发送的数据"
Copied!
5.关闭串口
1
serialPort.stopSerialPort(SerialPortManager.ttyCOM0);// 关闭串口/dev/ttyCOM0
Copied!
6.日志拦截(如需看日志,可设置日志拦截)
// 设置日志拦截
1
SerialPortManager.getInstances().setLogInterceptor(new LogInterceptorSerialPort() {
2
@Override
3
public void log(@SerialPortManager.Typefinal String type, final String port, final booleanisAscii, final String log) {
4
Log.d("SerialPortLog", new StringBuffer()
5
.append("串口号:").append(port)
6
.append("\n数据格式:").append(isAscii ? "ascii" : "hexString")
7
.append("\n操作类型:").append(type)
8
.append("操作消息:").append(log).toString());
9
}
10
});
Copied!
7.销毁SerialPortManager,销毁后在使用串口,需要重新执行初始化操作
1
SerialPortManager.getInstances().destroySerialPort();
Copied!

2.3.4 串口demo代码

1
packagecom.hyperlcd.serialport;
2
importandroid.os.Bundle;
3
importandroid.support.annotation.IdRes;
4
import android.support.v7.app.AppCompatActivity;
5
importandroid.text.TextUtils;
6
importandroid.util.Log;
7
importandroid.view.Gravity;
8
importandroid.view.View;
9
importandroid.widget.CompoundButton;
10
importandroid.widget.EditText;
11
importandroid.widget.RadioButton;
12
importandroid.widget.RadioGroup;
13
importandroid.widget.TextView;
14
importandroid.widget.Toast;
15
16
importandroid_serialport_api.hyperlcd.LogInterceptorSerialPort;
17
importandroid_serialport_api.hyperlcd.ReadListener;
18
importandroid_serialport_api.hyperlcd.SerialPort;
19
importandroid_serialport_api.hyperlcd.SerialPortManager;
20
21
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
22
23
privateRadioGroupcodeRG;
24
privateRadioGroupserialRG;
25
privateEditTextserialET;
26
privateEditTextsendET;
27
privateTextViewreadTV;
28
privateTextViewlogTV;
29
privateTextViewserialTitle;
30
privateTextViewcodeTitle;
31
32
private String currentPort;
33
privateSerialPortserialPort;
34
privateReadListenerreadListener;
35
privatebooleanisAscii;
36
37
@Override
38
protected void onCreate(Bundle savedInstanceState) {
39
super.onCreate(savedInstanceState);
40
setContentView(R.layout.activity_main);
41
42
initView();
43
44
initData();
45
}
46
47
private void initData() {
48
SerialPortManager.getInstances().initSerialPort();
49
SerialPortManager.getInstances().setLogInterceptor(new LogInterceptorSerialPort() {
50
@Override
51
public void log(@SerialPortManager.Type final String type, final String port, final booleanisAscii, final String log) {
52
Log.d("SerialPortLog", new StringBuffer()
53
.append("串口号:").append(port)
54
.append("\n数据格式:").append(isAscii ? "ascii" : "hexString")
55
.append("\n操作类型:").append(type)
56
.append("操作消息:").append(log).toString());
57
runOnUiThread(new Runnable() {
58
@Override
59
public void run() {
60
logTV.append(new StringBuffer()
61
.append(" ").append(port)
62
.append(" ").append(isAscii ? "ascii" : "hexString")
63
.append(" ").append(type)
64
.append(":").append(log)
65
.append("\n").toString());
66
}
67
});
68
}
69
});
70
71
serialPort = SerialPortManager.getInstances().getSerialPort();
72
readListener = new ReadListener() {
73
@Override
74
public void onRead(final String port, final booleanisAscii, final String read) {
75
Log.d("SerialPortRead", new StringBuffer()
76
.append(port).append("/").append(isAscii ? "ascii" : "hex")
77
.append(" read:").append(read).append("\n").toString());
78
runOnUiThread(new Runnable() {
79
@Override
80
public void run() {
81
readTV.append(new StringBuffer()
82
.append(port).append("/").append(isAscii ? "ascii" : "hex")
83
.append(" read:").append(read).append("\n").toString());
84
}
85
});
86
}
87
};
88
}
89
90
91
private void initView() {
92
codeRG = (RadioGroup) findViewById(R.id.rg_code);
93
serialRG = (RadioGroup) findViewById(R.id.rg_serial);
94
95
serialET = (EditText) findViewById(R.id.et_serial);
96
97
sendET = (EditText) findViewById(R.id.et_send);
98
serialTitle = (TextView) findViewById(R.id.title_serial);
99
codeTitle = (TextView) findViewById(R.id.title_code);
100
readTV = (TextView) findViewById(R.id.tv_read);
101
logTV = (TextView) findViewById(R.id.tv_log);
102
103
codeRG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
104
@Override
105
public void onCheckedChanged(RadioGroup group, @IdResintcheckedId) {
106
changeCode(checkedId == R.id.rb_ascii);
107
}
108
});
109
110
serialRG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
111
@Override
112
public void onCheckedChanged(RadioGroup group, @IdResintcheckedId) {
113
if (checkedId == R.id.rb_other) {
114
serialET.requestFocus();
115
} else {
116
sendET.requestFocus();
117
}
118
}
119
});
120
121
serialET.setOnFocusChangeListener(new View.OnFocusChangeListener() {
122
@Override
123
public void onFocusChange(View v, booleanhasFocus) {
124
if (hasFocus) {
125
serialRG.check(R.id.rb_other);
126
}
127
}
128
});
129
130
findViewById(R.id.btn_open).setOnClickListener(this);
131
findViewById(R.id.btn_close).setOnClickListener(this);
132
findViewById(R.id.clear_send).setOnClickListener(this);
133
findViewById(R.id.btn_send).setOnClickListener(this);
134
findViewById(R.id.clear_read).setOnClickListener(this);
135
findViewById(R.id.clear_log).setOnClickListener(this);
136
137
codeRG.check(R.id.rb_ascii);
138
serialRG.check(R.id.rb_com0);
139
sendET.requestFocus();
140
}
141
142
@Override
143
protected void onDestroy() {
144
SerialPortManager.getInstances().destroySerialPort();
145
super.onDestroy();
146
}
147
148
@Override
149
public void onClick(View v) {
150
switch (v.getId()) {
151
caseR.id.btn_open:
152
open();
153
break;
154
caseR.id.btn_close:
155
close();
156
break;
157
caseR.id.btn_send:
158
send();
159
break;
160
caseR.id.clear_send:
161
sendET.setText("");
162
break;
163
caseR.id.clear_read:
164
readTV.setText("");
165
break;
166
caseR.id.clear_log:
167
logTV.setText("");
168
break;
169
default:
170
}
171
}
172
173
private void send() {
174
if (serialPort == null) {
175
// 串口未初始化
176
T("串口未初始化");
177
return;
178
}
179
180
if (TextUtils.isEmpty(currentPort)) {
181
// 串口未打开
182
T("串口未打开");
183
return;
184
}
185
186
String send = sendET.getText().toString().trim();
187
if (TextUtils.isEmpty(send)) {
188
// 发送数据为空
189
T("发送数据为空");
190
return;
191
}
192
// 发送数据
193
try {
194
serialPort.writeSerialService(currentPort, isAscii, send);
195
} catch (Exception e) {
196
e.printStackTrace();
197
}
198
}
199
200
/**
201
* 打开串口
202
*/
203
private void open() {
204
if (serialPort == null) {
205
return;
206
}
207
String checkPort = getCurrentPort();
208
if (TextUtils.isEmpty(checkPort)) {
209
return;
210
} else if (TextUtils.equals(checkPort, SerialPortManager.other)) {
211
checkPort = serialET.getText().toString().trim();
212
if (TextUtils.isEmpty(checkPort)) {
213
T("请输入串口号");
214
return;
215
}
216
}
217
218
if (TextUtils.equals(currentPort, checkPort)) {
219
return;
220
}
221
222
if (!TextUtils.isEmpty(currentPort)) {
223
// 关闭currentPort串口
224
serialPort.stopSerialPort(currentPort);
225
}
226
227
isAscii = codeRG.getCheckedRadioButtonId() == R.id.rb_ascii;
228
currentPort = checkPort;
229
// 打开checkPort串口
230
serialPort.startSerialPort(checkPort, isAscii, readListener);
231
232
serialTitle.setText("串口:");
233
serialTitle.append(currentPort);
234
codeTitle.setText("数据格式:");
235
codeTitle.append(isAscii ? "ASCII" : "HexString");
236
}
237
238
/**
239
* 关闭串口
240
*/
241
private void close() {
242
if (!TextUtils.isEmpty(currentPort)) {
243
// 关闭currentPort串口
244
serialPort.stopSerialPort(currentPort);
245
currentPort = "";
246
serialTitle.setText("串口");
247
codeTitle.setText("数据格式");
248
}
249
}
250
251
/**
252
* 更改数据格式
253
*
254
* @paramisAsciitrue:asciifalse:HexString
255
*/
256
private void changeCode(booleanisAscii) {
257
if (TextUtils.isEmpty(currentPort)) {
258
return;
259
}
260
serialPort.setReadCode(currentPort, isAscii);
261
codeTitle.setText("数据格式:");
262
codeTitle.append(isAscii ? "ASCII" : "HexString");
263
}
264
265
/**
266
* 获取选中的串口号
267
*
268
* @return
269
*/
270
private String getCurrentPort() {
271
String checkPort;
272
switch (serialRG.getCheckedRadioButtonId()) {
273
case R.id.rb_com0:
274
checkPort = SerialPortManager.ttyCOM0;
275
break;
276
case R.id.rb_com1:
277
checkPort = SerialPortManager.ttyCOM1;
278
break;
279
case R.id.rb_com2:
280
checkPort = SerialPortManager.ttyCOM2;
281
break;
282
case R.id.rb_com3:
283
checkPort = SerialPortManager.ttyCOM3;
284
break;
285
case R.id.rb_s0:
286
checkPort = SerialPortManager.ttyS0;
287
break;
288
case R.id.rb_s1:
289
checkPort = SerialPortManager.ttyS1;
290
break;
291
case R.id.rb_s2:
292
checkPort = SerialPortManager.ttyS2;
293
break;
294
case R.id.rb_s3:
295
checkPort = SerialPortManager.ttyS3;
296
break;
297
caseR.id.rb_other:
298
checkPort = SerialPortManager.other;
299
break;
300
default:
301
checkPort = "";
302
}
303
returncheckPort;
304
}
305
306
private Toast toast;
307
privateTextViewtextView;
308
309
private void T(String message) {
310
if (toast == null) {
311
toast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
312
textView = new TextView(this);
313
textView.setTextColor(0xffffffff);
314
textView.setTextSize(30);
315
textView.setPadding(10, 5, 10, 5);
316
textView.setBackgroundResource(R.drawable.shape_toast_bg);
317
toast.setView(textView);
318
toast.setGravity(Gravity.CENTER, 0, 0);
319
}
320
textView.setText(message);
321
toast.show();
322
}
323
}
Copied!

2.4 开机自启动介绍

开机自启动一般有两种方式:一种接收开机广播后启动,一种将自己的APK设置成Launcher。前者开机会进入系统桌面后启动APK,后者开机跳过系统桌面直接进入APK。

2.4.1 接收开机广播后启动

当Android启动时,会发出一个系统广播,内容为”ACTION_BOOT_COMPLETED”。它的字符串常量表示为”android.intent.action.BOOT_COMPLETED”。只要在程序中“捕捉”到这个消息,再启动之即可。所以实现的手段就是实现一个BroadcastReceiver。
实现开机自启动主要实现就是修改应用程序具有laucher的权限。
第一步: 自定义广播类 BootReceiver
1
public class BootReceiver extends BroadcastReceiver {  
2
    @Override  
3
    public void onReceive(Context context, Intent intent) {  
4
        if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {     // boot  
5
            Intent intent2 = new Intent(context, MainActivity.class);  
6
//          intent2.setAction("android.intent.action.MAIN");  
7
//          intent2.addCategory("android.intent.category.LAUNCHER");  
8
            intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
9
            context.startActivity(intent2);  
10
        }  
11
    }  
12
}  
Copied!
第二步:清单文件配置
在AndroidManifest.xml中Application节点内,添加自定义的广播类
1
<receiver android:name="BootReceiver" >  
2
    <intent-filter>  
3
        <action android:name="android.intent.action.BOOT_COMPLETED" />  
4
  <category android:name="android.intent.category.LAUNCHER" />  
5
    </intent-filter>  
6
</receiver>  
Copied!
第三步:在AndroidManifest.xml中manifest节点内,添加开机启动权限
1
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Copied!

2.4.2 讲自己的APK设置成Launcher

替换配置文件中的第一个启动的 activity 的<intent-filter>
1
<activity
2
android:name="com.imstlife.mydoor.MainActivity"
3
android:configChanges="screenSize"
4
android:label="@string/app_name"
5
android:launchMode="singleTop">
6
<intent-filter>
7
<action android:name="android.intent.action.MAIN" />
8
9
<category android:name="android.intent.category.LAUNCHER" />
10
<category android:name="android.intent.category.HOME" />
11
<category android:name="android.intent.category.DEFAULT" />
12
<category android:name="android.intent.category.MONKEY" />
13
14
</intent-filter>
15
</activity>
Copied!
程序运行后点击Home,弹出Launcher选择框,选中自己开发的APK后点“始终”即可。

2.5 修改系统签名

修改系统签名的步骤如下:
1. 在AndroidManifest.xml配置文件manifest中加入android:sharedUserId="android.uid.system",直接用eclipse编译源代码产生.apk文件(具体代码中的实现请参考demo中的写法)
2. 把.apk文件重命名为.zip格式。用压缩软件打开,删掉META-INF目录下的CERT.SF和CERT.RSA两个文件。
3. 把删除后的文件,扩展名重命名回.apk格式。复制放在 f:/androidsource(此文件随便创建,建议不要有中文) 文件夹下。把附件中platform.pk8、platform.x509.pem、signapk.jar放在同一个文件夹中。
4. 进入cmd命令行,cd 到androidsource目录下再执行命令:
1
java -jar signapk.jar platform.x509.pem platform.pk8 SetSystemTime.apktest.apk
Copied!
5.如下图显示,系统签名修改完成(test.apk是需要输出的apk名称,名字可以自定义)。

2.6 APK加密

2.6.1 混淆代码

1.全局混淆选项,修改build/core/package.mk
1
ifndef LOCAL_PROGUARD_ENABLED
2
ifneq ($(filter user userdebug, $(TARGET_BUILD_VARIANT)),)
3
# turn on Proguard by default for user &userdebug build
4
LOCAL_PROGUARD_ENABLED :=full
5
Endif
Copied!
2.全局flag文件修改,屏蔽-dontobfuscate。修改build/core/proguard.flags
1
# Don't obfuscate. We only need dead code striping.
2
#-dontobfuscate
Copied!
3.在自己模块下创建proguard.cfg文件,用来配置混淆选项
4.在Android.mk里每个package类型的LOCAL_MODULE里LOCAL_PACKAGE_NAME下面添加两句指令:
1
LOCAL_PROGUARD_ENABLED := full #指定当前的应用打开混淆
2
LOCAL_PROGUARD_FLAG_FILES := proguard.cfg #指定混淆配置文件
Copied!
5.编译时设置环境变量使用. ./setenv.sh -bv user
6.遇到报错需要就需要修改proguard.cfg文件,规则可以找google。

2.6.2 防止二次打包

1.Java 代码中加入签名校验(直接修改smali文件)
2.NDK 中加入签名校验(ida查看直接hex修改)
3.利用二次打包工具本身的缺陷阻止打包(manifest 欺骗,图片修改后缀等等)

2.6.3 使用第三方加密工具对DEX、RES、SO库的高级加密

1.导出apk(部分第三方加密平台需要导出签名的apk)
2.第三方平台加固(生成多渠道包)
现在比较流行的加密平台有:
如果项目里面包含了类似百度统计、友盟统计等功能,那么肯定需要了解不同应用商店的下载量,所以生成渠道包就很重要。这些平台都可以帮助生成多个渠道的apk。
3.apk重新签名
加固后的apk是没有签名的,而没有签名的apk是无法安装到手机里面的,因此可以通过使用签名工具重新签名。adt自带的签名工具由于过于麻烦,建议使用第三方的签名工具,例如:爱加密提供的签名工具http://www.ijiami.cn/apply/Sign

2.7 蜂鸣器使用(仅部分屏支持)

蜂鸣器是一种一体化结构的电子讯响器,它采用直流电压供电,在电子产品中作发声器件。蜂鸣器由GPIO控制实现发声。其代码如下:
第一步:创建RootShellCmd类
1
public class RootShellCmd {
2
/**
3
* 打开蜂鸣器
4
*/
5
public static void openBuzzer_new() throws IOException, InterruptedException {
6
exec("echo default-on > /sys/class/leds/beep/trigger\n");
7
execNoTry("echo none > /sys/class/leds/beep/trigger");
8
}
9
10
/**
11
* 关闭蜂鸣器
12
*/
13
public static void closeBuzzer_new() throws IOException, InterruptedException {
14
execNoTry("echo default-on > /sys/class/leds/beep/trigger");
15
}
16
public static void execNoTry(String... cmds) throws IOException, InterruptedException {
17
18
StringBuffer command = new StringBuffer();
19
if (cmds.length <= 0) {
20
return;
21
}
22
for (String cmd : cmds) {
23
command.append(cmd).append("\n");
24
}
25
26
Process process = null;
27
DataOutputStream os = null;
28
29
try {
30
process = Runtime.getRuntime().exec("su");
31
os = new DataOutputStream(process.getOutputStream());
32
os.write(command.toString().getBytes());
33
os.writeBytes("exit\n");
34
os.flush();
35
//执行命令
36
process.waitFor();
37
} catch (Exception e) {
38
e.printStackTrace();
39
throw e;
40
} finally {
41
try {
42
os.close();
43
} catch (IOException e) {
44
e.printStackTrace();
45
}
46
process.destroy();
47
}
48
}
49
50
}
Copied!
第二步:在MainActivity中调用控制蜂鸣器发声的方法
1
RootShellCmdrootShellCmd = new RootShellCmd();
2
rootShellCmd.openBuzzer_new();//控制蜂鸣器发声
3
rootShellCmd.closeBuzzer_new();//停止发声
Copied!

2.8 固件烧录程序

第一步:将屏连接电脑,打开安卓开发工具V2.1
第二步:双击进入测试文件,点击升级固件,进入固件选择界面
第三步:连接设备,选择需要烧录的固件
第四步:连接后软件显示(发现一个MSC设备)表示已经连接识别
第五步:点击切换(显示切换MSC成功)
注:如无法加载固件,请安装驱动。
第六步:点击升级,开始自动加载

2.9 开机配置

进行开机配置需要安装固件工厂工具。

2.9.1 画面配置

画面配置可以用来查看替换内核图片,Android开机动画,默认壁纸和充电动画。

2.9.2 开机Logo修改

开机Logo可以通过如下步骤进行更改:

2.9.2.1 内核Logo的生成

可以使用bin\目录下FirmwareToPPM.exe来转换成所需的224 ppm的图片,支持图片的格式ppm,bmp,jpg,png,转换出来图片可以放到内核中参加编译。

2.9.2.2 开机Logo的修改

点击“Replace boot logo”按钮,选择需要替换的开机logo,工具会根据你固件中的logo 图片格式自动过滤出符合内核logo 的图片,可以根据文件类型选择符合要求的图片,支持的图片格式ppm, bmp, jpg, png.
注意:内核配置为Bmp Logo 的固件可支持多分辨率的替换,替换logo的最大分辨率和显示logo的分辨率如下图所示

2.9.3 修改开机动画

2.9.3.1 制作开机动画

开机动画的文件是bootanimation.zip,该文件中包含part0 和desc.txt 两部分:
1. part0:该文件夹下放置开机显示的动画图片,图片分辨率必须和机器分辨率一致,否则显示会有问题。
2. desc.txt:此文件要在Linux 系统下生成。文件参数如下(以分辨率800*480 的屏为例):
参数
说明
800 480 10
800 480 -- 屏幕分辨率(宽*高);
10 -- 每秒播放的图片张数;
P 0 0 part0
P – 播放;
0 – 0表示循环播放;1表示单次播放;
0 – 延时时间;
Part0 – 存储动画文件的文件夹。
修改完毕并替换part0下的开机动画之后,按如下方式压缩文件(必须选择zip 和存储的压缩方式)。压缩完成后要双击打开压缩文件查看是否有多余文件,若有则将其删掉,否则开机没有动画。

2.9.3.2 替换开机动画

1.打开固件工厂工具
2.点击固件,打开需要修改的固件
注:固件需要时可提供
3.解包固件
4.固件里没有包含开机动画,点击确定
5.点击替换开机动画按钮、将2.9.3.1制作好的开机动画导入
6.可预览开机动画的效果
7.修改完成后点击保存
注意:保存的文件命名格式以.img结尾

2.10 其他

第一步:导入RootShellCmd.java工具类
第二步:在主类中调用

2.10.1 调节屏幕亮度

1
RootShellCmd.getInstance().setBrightness(0);
Copied!

2.10.2 Home键

1
RootShellCmd.getInstance().home();
Copied!

2.10.3 Back键

1
RootShellCmd.getInstance().back();
Copied!

2.10.4 动态关机

1
RootShellCmd.getInstance().shutDown();
Copied!

2.10.5 动态重启

1
RootShellCmd.getInstance().reboot();
Copied!