原文地址:http://www.pocketdigi.com/20130519/1058.html
Android中有些Api被隐藏了,比如开关机,重启,如果要在应用中调用,要么用反射,要么就是直接在Android源代码下编译。如果用Eclipse用IDE,尽管调用隐藏API的代码能顺利在Android源码下通过编译,但Eclipse找不到相应的类,会报错,为了写代码时方便点,我们可以把相关的包加到eclipse中。 先下载Android源码(本站有提供4.2.2的打包下载链接,自己找找),编译一次,找到out/target/common/obj/JAVA_LIBRARIES/fmradioif_intermediates/classes.jar,在Eclispe中加到我们自己项目的构建路径中,这样就可以调用到相关的类了。另外,这个包里的有些类和方法,跟android.jar是有冲突的,我们得手工调整优先级,打开项目属性,找到Java构建路径,排序和导出,把刚刚添加的classes.jar放到最顶上。 另外,我们需要调用的API,源代码都在frameworks/base/core/java下,根据包名找。 下面的例子是关机的,项目名为PowerOff。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.example.poweroff ;
import android.app.Activity ;
import android.os.Bundle ;
import android.os.IPowerManager ;
import android.os.RemoteException ;
import android.os.ServiceManager ;
import android.view.Menu ;
import android.view.View ;
import android.view.View.OnClickListener ;
import android.widget.Button ;
public class MainActivity extends Activity {
@Override
protected void onCreate( Bundle savedInstanceState) {
super .onCreate ( savedInstanceState) ;
setContentView( R.layout .activity_main ) ;
Button button1= ( Button ) findViewById( R.id .button1 ) ;
button1.setOnClickListener ( new OnClickListener( ) {
@Override
public void onClick( View v) {
// TODO Auto-generated method stub
IPowerManager power= IPowerManager.Stub .asInterface ( ServiceManager.getService ( "power" ) ) ;
if ( power!= null )
{ packages/ apps
try {
/**
* 查看frameworks/base/core/java/android/os/IPowerManager.aidl
* void shutdown(boolean confirm, boolean wait);
* 所以,第一个是是否让用户确认,第二个是是否等待
*/
power.shutdown ( false ,false ) ;
} catch ( RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace ( ) ;
}
}
}
} ) ;
}
@Override
public boolean onCreateOptionsMenu( Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater( ) .inflate ( R.menu .main , menu) ;
return true ;
}
}
AndroidManifest.xml:需要重启权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version ="1.0" encoding ="utf-8" ?>
<manifest xmlns:android ="http://schemas.android.com/apk/res/android"
package ="com.example.poweroff"
android:versionCode ="1"
android:versionName ="1.0" >
<uses-sdk
android:minSdkVersion ="8"
android:targetSdkVersion ="17" />
<!-- 加入这条,Eclipse会报错,提示Permission is only granted to system apps,只有系统app才能调用,没关系,反正我们不用eclipse编译 -->
<uses-permission android:name ="android.permission.REBOOT" />
<application
android:allowBackup ="true"
android:icon ="@drawable/ic_launcher"
android:label ="@string/app_name"
android:theme ="@style/AppTheme" >
<activity
android:name ="com.example.poweroff.MainActivity"
android:label ="@string/app_name" >
<intent-filter>
<action android:name ="android.intent.action.MAIN" />
<category android:name ="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
项目根目录下,创建一个Android.mk文件,内容如下: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := PowerOff LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE)
注意LOCAL_MODULE_TAGS := optional,可能有四个值user,eng,tests,optional,对应你编译Android源码时的参数,optional兼容所有。 另外,布局的xml中,android:text属性要用引用,先写到strings.xml里,直接hard code会报错. 编译: 切到android源代码根目录,设环境变量 执行/build/envsetup.sh 把项目拷到packages/apps目录下,切换到packages/apps/PowerOff目录,把Eclipse自动生成的gen目录删除,执行mm开始编译。 成功后,会提示Install: out/target/product/maguro/system/app/PowerOff.apk 但是正常能安装的文件在 out/target/product/maguro/obj/APPS/PowerOff_intermediates/package.apk,如果安装上面那个,可能会出现INSTALL_FAILED_DEXOPT错误 再用 adb install装上,成功关机. 有一点需要注意,我的手机是Galaxy Nexus,刚刚刷上自己用源码编译的Rom,如果是其他手机,还是需要系统签名先。