android中两个app之间利用广播互相监听
2016-05-25 16:15
393 查看
今天去面试,什么公司就不谈了,技术官直接就上需求让我思考一下,自己就写了一个小demo,效果还可以,奉献一下,源码要的邮箱,我就不上传了。
按照惯例先贴出需求:
需求:
1.apk2终止时发送广播,apk1接受,然后启动apk2。
2.主动:当apk2被卸载后,apk1查询是否卸载,然后安装apk2。
3.被动:apk2当应用被卸载后,系统发出广播,apk1接受判断后安装apk2。
自己做了一个demo,效果如下:
1.安装test1后,点击button,开始检测test2,查的没有test2,开始下载。
2.下载test2后,退出test2,提示4秒后开启test2,test2开启。
3.卸载test2,提示test1已卸载,然后4秒后重装test2。
test1项目结构:
test2项目结构:
一,test1部分
MainActivity的代码如下:
MyReceiver的代码如下:
xml文件配置如下:
二,test2部分
xml文件配置如下:
按照惯例先贴出需求:
需求:
1.apk2终止时发送广播,apk1接受,然后启动apk2。
2.主动:当apk2被卸载后,apk1查询是否卸载,然后安装apk2。
3.被动:apk2当应用被卸载后,系统发出广播,apk1接受判断后安装apk2。
自己做了一个demo,效果如下:
1.安装test1后,点击button,开始检测test2,查的没有test2,开始下载。
2.下载test2后,退出test2,提示4秒后开启test2,test2开启。
3.卸载test2,提示test1已卸载,然后4秒后重装test2。
test1项目结构:
test2项目结构:
一,test1部分
MainActivity的代码如下:
public class MainActivity extends Activity implements OnClickListener,BRInteraction { private Button app1Btn; private MyReceiver myReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initBroadcastReciver(); setListener(); } ------------------------------------------------------------ //初始化broadcastreceiver private void initBroadcastReciver() { IntentFilter intentFilter1 = new IntentFilter(); intentFilter1.addAction("app2isclosed"); IntentFilter intentFilter2 = new IntentFilter(); intentFilter2.addAction("android.intent.action.PACKAGE_REMOVED"); intentFilter2.addDataScheme("package"); myReceiver = new MyReceiver(); registerReceiver(myReceiver, intentFilter1); registerReceiver(myReceiver, intentFilter2); } //初始化view private void initViews() { app1Btn = (Button) findViewById(R.id.app1_btn); } //设置监听 private void setListener() { app1Btn.setOnClickListener(this); myReceiver.setBRInteractionListener(this); } -------------------------------------------------- @Override public void onClick(View v) { switch (v.getId()) { case R.id.app1_btn: switchApp2(); break; default: break; } } //启动app2,如果没有开始下载 public void switchApp2() { if (hasApplication()) { ComponentName componetName = new ComponentName( // 这个是另外一个应用程序的包名 "com.example.test2", // 这个参数是要启动的Activity "com.example.test2.MainActivity"); Intent intent = new Intent(); intent.setComponent(componetName); startActivity(intent); } else { Toast.makeText(MainActivity.this, "没有安装test2,正在安装", Toast.LENGTH_LONG) .show(); installApk(); } } //下载app2 @Override public void installApk() { new Handler().postDelayed(new Runnable() { public void run() { slientInstall(); // 未安装进行安装 } }, 2 * 1000); } //判断是否存在test2 public boolean hasApplication() { PackageManager packageManager = getPackageManager(); // 查询是否有该Intent的Activity Intent in = new Intent(); in.setClassName("com.example.test2", "com.example.test2.MainActivity"); List<ResolveInfo> activities = packageManager.queryIntentActivities(in, 0); Log.i("----tag-----", "activities" + activities.size()); // activities里面不为空就有,否则就没有 return activities.size() > 0 ? true : false; } //当接受到app2发送的广播,回调 @Override public void app2IsClosedcallBack(String content) { Log.i("-----tag------", "content:" + content); new Handler().postDelayed(new Runnable() { public void run() { switchApp2(); } }, 4 * 1000); } /*----------------------安装apk2---------------------*/ /** * 静默安装 * * @param file * @return */ public boolean slientInstall() { createFile(); // 进行资源的转移 将assets下的文件转移到可读写文件目录下 File file = new File(Environment.getExternalStorageDirectory() .getPath() + "/temp.apk"); boolean result = false; Process process = null; OutputStream out = null; System.out.println(file.getPath()); if (file.exists()) { System.out.println(file.getPath() + "=="); try { process = Runtime.getRuntime().exec("su"); out = process.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(out); dataOutputStream.writeBytes("chmod 777 " + file.getPath() e989 + "\n"); // 获取文件所有权限 dataOutputStream .writeBytes("LD_LIBRARY_PATH=/vendor/lib:/system/lib pm install -r " + file.getPath()); // 进行静默安装命令 // 提交命令 dataOutputStream.flush(); // 关闭流操作 dataOutputStream.close(); out.close(); int value = process.waitFor(); // 代表成功 if (value == 0) { Log.e("hao", "安装成功!"); result = true; } else if (value == 1) { // 失败 Log.e("hao", "安装失败!"); result = false; } else { // 未知情况 Log.e("hao", "未知情况!"); result = false; } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } if (!result) { Log.e("hao", "root权限获取失败,将进行普通安装"); Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); startActivity(intent); result = true; } } return result; } public void createFile() { InputStream is = null; FileOutputStream fos = null; try { is = MainActivity.this.getAssets().open("test2.apk"); File file = new File(Environment.getExternalStorageDirectory() .getPath() + "/temp.apk"); file.createNewFile(); fos = new FileOutputStream(file); byte[] temp = new byte[1024]; int i = 0; while ((i = is.read(temp)) > 0) { fos.write(temp, 0, i); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(myReceiver); } }
MyReceiver的代码如下:
/** * * @ClassName: MyReceiver * @Description:用来检测APP2和系统的广播 * @author guang.hu * @date 2016年5月25日 上午11:16:55 * * */ public class MyReceiver extends BroadcastReceiver{ private BRInteraction brInteraction; @Override public void onReceive(Context context, Intent intent) { //app2关闭时,这里接受广播 if(intent.getAction().equals("app2isclosed")){ String name = intent.getExtras().getString("name"); Toast.makeText(context, name, Toast.LENGTH_SHORT).show(); brInteraction.app2IsClosedcallBack(name); } //当有程序卸载时,系统发送广播,这里接受 if(intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) { String packageName = intent.getDataString(); if(packageName.equals("package:com.example.test2")){ Toast.makeText(context, "app2已卸载,正在重装", Toast.LENGTH_SHORT).show(); brInteraction.app2IsClosedcallBack("app2已卸载,正在重装"); } } } ---------------------------------------- //自定义接口实现对app2退出的处理,卸载app2后的处理 public interface BRInteraction { public void app2IsClosedcallBack(String content); } ---------------------------------------- public void setBRInteractionListener(BRInteraction brInteraction) { this.brInteraction = brInteraction; } }
xml文件配置如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test1" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
二,test2部分
public class MainActivity extends Activity implements OnClickListener { private Button app2Btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); setListener(); } private void initViews() { app2Btn = (Button) findViewById(R.id.app2_btn); } private void setListener() { app2Btn.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.app2_btn: switchApp1(); break; default: break; } } //启动app1 public void switchApp1() { if (hasApplication()) { ComponentName componetName = new ComponentName( // 这个是另外一个应用程序的包名 "com.example.test1", // 这个参数是要启动的Activity "com.example.test1.MainActivity"); Intent intent = new Intent(); intent.setComponent(componetName); startActivity(intent); } else { Toast.makeText(MainActivity.this, "没有安装test1", Toast.LENGTH_LONG) .show(); } } //当程序中终止时,发送广播 private void mySendBroadcast() { Intent intent = new Intent(); intent.setAction("app2isclosed"); intent.putExtra("name", "app2 is closed,4秒后重启"); MainActivity.this.sendBroadcast(intent); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); mySendBroadcast(); } //判断是否存在test1 public boolean hasApplication() { PackageManager packageManager = getPackageManager(); // 查询是否有该Intent的Activity Intent in = new Intent(); in.setClassName("com.example.test1", "com.example.test1.MainActivity"); List<ResolveInfo> activities = packageManager.queryIntentActivities(in, 0); Log.i("----tag-----", "activities" + activities.size()); // activities里面不为空就有,否则就没有 return activities.size() > 0 ? true : false; } }
xml文件配置如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test2" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask" 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>