360儿童英语 app推荐app进去直接到了推荐的界面,怎么进去以前微聊的界面。

不知道怎么开发VR游戏?【系列4】VR中的用户界面
招聘信息:
本文转自:,作者:王寒在设计VR应用的用户界面时要考虑很多因素,而这些因素对于传统应用或游戏的界面设计可能都不是事儿。下面我们会看看作为一个VR开发者在设计用户界面时可能会遇到的一些问题,以及跟硬件相关的一些东西。UI分辨率和画质目前DK2的分辨率是(单目是960*1080),而Gear VR是(单目是),因此对任何在宽度或高度上要占据几个像素的物体,都会出现比较明显的像素化现象。其实特别要注意的是UI元素,记住它们在屏幕上要显示的大小。一个简单的原则是尽量使用大一点字体或粗体字,另外就是尽量不要使用在VR场景中容易变得像素化的细纹。UI的类型Non-diegetic(非剧情型UI)在传统的非VR项目中,UI通常显示在界面的顶部,用来显示生命值、得分之类的信息,通常被称为HUD。这就是所谓的非剧情型UI-用户界面跟游戏世界没有什么关联度,但是对玩游戏的玩家有一定的作用。在电影中也有所谓的“画外音”,比如电影或电视中的背景音乐。与此不同的是,剧情音通常跟故事紧密相连-比如角色之间的对话,或是实际发生的自然音效。在Unity中,添加HUD样式的非剧情型UI相对简单,只需要在UI Canvas的Render Mode中选择使用Screen Space- Overlay或是Screen Space- Camera。但这种UI界面对VR基本不适用,我们的眼镜无法聚焦在如此近的物体上,而Unity VR中根本就不支持Screen Space-Overlay。Spatial UI(空间UI)和前一种UI不同的是,我们需要将UI放置到环境之中,并在Canvas的Render Mode中选择使用World Space模式。通过这种方式,就可以让用户的眼镜聚焦到UI上。这就是所谓的Spatial UI(空间UI)。将UI元素放在世界的哪个位置也需要认真考虑。太靠近用户会导致眼部疲劳,离得太远会感觉聚焦在地平线上-这种情况可能发生在室外环境,而不是在小屋子里。此外我们还需要对UI的比例进行适当调整,具体要根据产品的实际需求来定。我们最好把UI放在一个舒适的可读距离,并进行相应的缩放。关于这一点可以参考Main Menu场景中的UI:它被放置在几米远的位置,因此图片和文字都比较大,看起来很舒服。当我们把UI放在离用户有一定距离的时候,可能会发现UI重叠到其它物体上。关于这一点可以查看,看看如何修改shader让其绘制在其它对象上,或者直接使用VR Samples项目中的shader。这个shader也适用于文本。很多开发者想要把UI关联到摄像机上,这样当玩家移动的时候,UI会保持在一个固定的位置。这样做对十字准星或其它小物体可能会比较合适,不过对于比较大的UI元素,就好比把一张报纸放到你的脸上,很容易让用户感到不舒服,甚至是眩晕。我们可以看一看Shooter 360(Target Arena)场景中的UI,其中UI会在一个较短的延迟后移动到视野中,从而可以让用户四处查看进而熟悉身边的环境,而不是直接把UI固定到他们的视野中,导致视觉模糊。虽然VR可以让用户探索360度沉浸式环境,不过有时候我们需要提醒用户关注某个特定的方向。在某些场景中,我们使用世界中的箭头来帮助引导用户的注意力。这些箭头会根据用户的朝向来淡入淡出。这些功能可以在GUIArrows 预设中找到,而且很容易重用。其工作原理是比较用户头部和目标方向之间的角度。如果头部在预设角度之外(参考下面GUIArrows组件的Show Angle),箭头就会淡入。当用户向目标的方向注视时,箭头就会开始淡出。Diegetic UI(剧情型UI)Spatial UI的替代方案是让环境中的物体自行向用户展示信息。具体的形式可能是墙上的闹钟,电视、计算机屏幕、移动手机,或是未来枪械的全息展示。这就是所谓的剧情型UI。下图展示了Flyer场景中的太空飞船,以及Shooter(Target)场景中的枪支。虽然这种交互不算严格意义上的剧情型UI,但是将用户界面跟游戏对象关联在一起,可以让我们大概了解Unity的剧情型UI是如何工作的。关于UI的延伸阅读信息关于UI类型的更详细分析(不涉及到VR),可以参考这篇文章:UI交互通过使用Interaction in VR一文中所提到的VREyeRaycaster, VRInput和VRInteractiveItem,我们可以创建基本的UI交互元素,具体方法是创建一个订阅VRInteractiveItem事件的类。关于这一点的更多信息,可以参考,特别是Maze场景中的switch。此外,在VRSamples中每个游戏的开始,我们都使用了UI交互指导用户。关于如何在VR中使用Unity UI,可以,其中还提供了示例代码。VR Samples场景中的UI接下来让我们看看以上所提到的概念在VR Samples场景中的具体实现:Menu(菜单)场景Menu场景中的UI使用了定制的纹理来创造一个弯曲的密封环境。可以使用Interaction in VR一文中的相同方法跟这些纹理进行交互。Flyer场景游戏简介和游戏结束的UI使用静态的方式放置在世界空间中。不过为了呈现跟游戏相关的信息,我们可以使用跟太空飞船关联的世界空间UI,也就是剧情型UI。考虑到飞船必须时刻出现在用户的视野中,因此在飞船四周显示相关信息是靠谱的。与此同时,UI元素会旋转以面向摄像机,这样就会避免倾斜,同时确保UI的显示对用户友好。Maze场景在Maze 场景中,我们使用Spatial UI来提供游戏引导和结束。Spatial UI还可以用来提示用户进行交互:Shooter 180(Target Gallery)场景在游戏引导和结束部分,我们再次使用了静态的Spatial UI。正如上面所提到的,我们在枪支上使用剧情型UI来显示倒计时和得分Shooter 360(Target Arena)场景在这个场景中依然使用了Spatial UI,不过做了一些小的调整:当360度竞技场中发生了某个动作,比如当用户四处查看环境时,我们会让UI元素在经过一个短时间的延迟后移动到视野中间。通过这种方式可以让用户知道四处探查所处的环境。在枪支上我们再次使用了剧情型UI。VR中的文本抗锯齿为了在VR世界中实现免费的文本抗锯齿效果,这里有一个小技巧,在Worldspace Canva中使用Canvas Scaler。在相关设置中,我们需要将”Reference Pixels Per Unit”设置为1,然后调整”Dynamic Pixels Per Unit”,直到文本的边缘柔化。在下图中,我们可以看到不同设置的实际显示效果。看完本教程,我们对不同的用户界面应该有了基本的概念,也知道在VR中应该使用哪种UI。当然,我们还可以使用VREyeRaycaster,VRInput和VRInteractiveItem来创建基本的UI交互。
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量5346点击量5146点击量5092点击量4946点击量3811点击量3718点击量3519点击量2880点击量2672
&2016 Chukong Technologies,Inc.
京公网安备89360儿童卫士app怎么发软文有吸引力_百度知道
360儿童卫士app怎么发软文有吸引力
360儿童卫士app怎么发软文有吸引力
我有更好的答案
360:在App Store(iOS)或360手机助手及其他应用市场中(Android)中搜索“360儿童卫士”进行下载方法三.mall.360.com/:打开手机浏览器.com/" target="_blank">http://baby,进入360儿童卫士官网://baby.mall:<a href="http在手机端下载安装360儿童卫士App的方法:方法一:扫描二维码,进入App下载页面方法二,点击“APP下载”进行下载希望能有帮助
数码爱好者
你好360儿童卫士APP里没有这样的功能。它是管理儿童手表的。
为您推荐:
您可能关注的内容
&#xe675;换一换
回答问题,赢新手礼包&#xe6b9;
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。360儿童卫士app进去直接到了推荐的界面,怎么进去以前微聊的界面,不知_百度知道
360儿童卫士app进去直接到了推荐的界面,怎么进去以前微聊的界面,不知
360儿童卫士app进去直接到了推荐的界面,怎么进去以前微聊的界面,不知道从那里找以前微聊、足迹等。
我有更好的答案
你好朋友你可以安装最新的360儿童卫士APP,登录后在微聊里就可以找到。
采纳率:55%
来自团队:
为您推荐:
其他类似问题
&#xe675;换一换
回答问题,赢新手礼包&#xe6b9;
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。Android静默安装实现方案,仿360手机助手秒装和智能安装功能
之前有很多朋友都问过我,在中怎样才能实现静默安装呢?所谓的静默安装,就是不用弹出系统的安装界面,在不影响用户任何操作的情况下不知不觉地将程序装好。虽说这种方式看上去不打搅用户,但是却存在着一个问题,因为Android系统会在安装界面当中把程序所声明的权限展示给用户看,用户来评估一下这些权限然后决定是否要安装该程序,但如果使用了静默安装的方式,也就没有地方让用户看权限了,相当于用户被动接受了这些权限。在Android官方看来,这显示是一种非常危险的行为,因此静默安装这一行为系统是不会开放给开发者的。
但是总是弹出一个安装对话框确实是一种体验比较差的行为,这一点Google自己也意识到了,因此Android系统对自家的Google Play商店开放了静默安装权限,也就是说所有从Google Play上下载的应用都可以不用弹出安装对话框了。这一点充分说明了拥有权限的重要性,自家的系统想怎么改就怎么改。借鉴Google的做法,很多国内的手机厂商也采用了类似的处理方式,比如说小米手机在小米商店中下载应用也是不需要弹出安装对话框的,因为小米可以在MIUI中对Android系统进行各种定制。因此,如果我们只是做一个普通的应用,其实不太需要考虑静默安装这个功能,因为我们只需要将应用上架到相应的商店当中,就会自动拥有静默安装的功能。
但是如果我们想要做的也是一个类似于商店的平台呢?比如说像360手机助手,它广泛安装于各种各样的手机上,但都是作为一个普通的应用存在的,而没有Google或小米这样的特殊权限,那360手机助手应该怎样做到更好的安装体验呢?为此360手机助手提供了两种方案, 秒装(需ROOT权限)和智能安装,如下图示:
因此,今天我们就模仿一下360手机助手的实现方式,来给大家提供一套静默安装的解决方案。
所谓的秒装其实就是需要ROOT权限的静默安装,其实静默安装的原理很简单,就是调用Android系统的pm install命令就可以了,但关键的问题就在于,pm命令系统是不授予我们权限调用的,因此只能在拥有ROOT权限的手机上去申请权限才行。
下面我们开始动手,新建一个InstallTest项目,然后创建一个SilentInstall类作为静默安装功能的实现类,代码如下所示:
* 静默安装的实现类,调用install()方法执行具体的静默安装逻辑。
public class SilentInstall {
* 执行具体的静默安装逻辑,需要手机ROOT。
* @param apkPath
要安装的apk文件的路径
* @return 安装成功返回true,安装失败返回false。
public boolean install(String apkPath) {
boolean result =
DataOutputStream dataOutputStream =
BufferedReader errorStream =
// 申请su权限
Process process = Runtime.getRuntime().exec(&su&);
dataOutputStream = new DataOutputStream(process.getOutputStream());
// 执行pm install命令
String command = &pm install -r & + apkPath + &\n&;
dataOutputStream.write(command.getBytes(Charset.forName(&utf-8&)));
dataOutputStream.flush();
dataOutputStream.writeBytes(&exit\n&);
dataOutputStream.flush();
process.waitFor();
errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String msg = &&;
// 读取命令的执行结果
while ((line = errorStream.readLine()) != null) {
Log.d(&TAG&, &install msg is & + msg);
// 如果执行结果中包含Failure字样就认为是安装失败,否则就认为安装成功
if (!msg.contains(&Failure&)) {
} catch (Exception e) {
Log.e(&TAG&, e.getMessage(), e);
} finally {
if (dataOutputStream != null) {
dataOutputStream.close();
if (errorStream != null) {
errorStream.close();
} catch (IOException e) {
Log.e(&TAG&, e.getMessage(), e);
可以看到,SilentInstall类中只有一个install()方法,所有静默安装的逻辑都在这个方法中了,那么我们具体来看一下这个方法。首先在第21行调用了Runtime.getRuntime().exec(&su&)方法,在这里先申请ROOT权限,不然的话后面的操作都将失败。然后在第24行开始组装静默安装命令,命令的格式就是pm install -r ,-r参数表示如果要安装的apk已经存在了就覆盖安装的意思,apk路径是作为方法参数传入的。接下来的几行就是执行上述命令的过程,注意安装这个过程是同步的,因此我们在下面调用了process.waitFor()方法,即安装要多久,我们就要在这里等多久。等待结束之后说明安装过程结束了,接下来我们要去读取安装的结果并进行解析,解析的逻辑也很简单,如果安装结果中包含Failure字样就说明安装失败,反之则说明安装成功。
&?xml version=&1.0& encoding=&utf-8&?&
&manifest xmlns:android=&https://schemas.android.com/apk/res/android&
package=&com.example.installtest&&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE& /&
&application
android:allowBackup=&true&
android:icon=&@mipmap/ic_launcher&
android:label=&@string/app_name&
android:supportsRtl=&true&
android:theme=&@style/AppTheme&&
&activity android:name=&.MainActivity&&
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&category android:name=&android.intent.category.LAUNCHER& /&
&/intent-filter&
&/activity&
&activity android:name=&.FileExplorerActivity&/&
&/application&
&/manifest&
整个方法还是非常简单易懂的,下面我们就来搭建调用这个方法的环境。修改activity_main.xml中的代码,如下所示:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&https://schemas.android.com/apk/res/android&
xmlns:tools=&https://schemas.android.com/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical&
android:paddingBottom=&@dimen/activity_vertical_margin&
android:paddingLeft=&@dimen/activity_horizontal_margin&
android:paddingRight=&@dimen/activity_horizontal_margin&
android:paddingTop=&@dimen/activity_vertical_margin&
tools:context=&com.example.installtest.MainActivity&&
&LinearLayout
android:layout_width=&match_parent&
android:layout_height=&wrap_content&&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:onClick=&onChooseApkFile&
android:text=&选择安装包& /&
android:id=&@+id/apkPathText&
android:layout_width=&0dp&
android:layout_height=&wrap_content&
android:layout_weight=&1&
android:layout_gravity=&center_vertical&
&/LinearLayout&
android:layout_width=&match_parent&
android:layout_height=&1dp&
android:background=&@android:color/darker_gray& /&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:onClick=&onSilentInstall&
android:text=&秒装& /&
android:layout_width=&match_parent&
android:layout_height=&1dp&
android:background=&@android:color/darker_gray& /&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:onClick=&onForwardToAccessibility&
android:text=&开启智能安装服务& /&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:onClick=&onSmartInstall&
android:text=&智能安装& /&
&/LinearLayout&
这里我们先将程序的主界面确定好,主界面上拥有四个按钮,第一个按钮用于选择apk文件的,第二个按钮用于开始秒装,第三个按钮用于开启智能安装服务,第四个按钮用于开始智能安装,这里我们暂时只能用到前两个按钮。那么调用SilentInstall的install()方法需要传入apk路径,因此我们需要先把文件选择器的功能实现好,新建activity_file_explorer.xml和list_item.xml作为文件选择器的布局文件,代码分别如下所示:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout
xmlns:android=&https://schemas.android.com/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:padding=&4dp&
android:orientation=&horizontal&&
&ImageView android:id=&@+id/img&
android:layout_width=&32dp&
android:layout_margin=&4dp&
android:layout_gravity=&center_vertical&
android:layout_height=&32dp&/&
&TextView android:id=&@+id/name&
android:textSize=&18sp&
android:textStyle=&bold&
android:layout_width=&match_parent&
android:gravity=&center_vertical&
android:layout_height=&50dp&/&
&/LinearLayout&
然后新建FileExplorerActivity作为文件选择器的Activity,代码如下:
public class FileExplorerActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
ListView listV
String rootPath = Environment.getExternalStorageDirectory().getPath();
String currentPath = rootP
List<map& list = new ArrayList&&();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_explorer);
listView = (ListView) findViewById(R.id.list_view);
adapter = new SimpleAdapter(this, list, R.layout.list_item,
new String[]{&name&, &img&}, new int[]{R.id.name, R.id.img});
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
refreshListItems(currentPath);
private void refreshListItems(String path) {
setTitle(path);
File[] files = new File(path).listFiles();
list.clear();
if (files != null) {
for (File file : files) {
Map map = new HashMap&&();
if (file.isDirectory()) {
map.put(&img&, R.drawable.directory);
map.put(&img&, R.drawable.file_doc);
map.put(&name&, file.getName());
map.put(&currentPath&, file.getPath());
list.add(map);
adapter.notifyDataSetChanged();
public void onItemClick(AdapterView parent, View v, int position, long id) {
currentPath = (String) list.get(position).get(&currentPath&);
File file = new File(currentPath);
if (file.isDirectory())
refreshListItems(currentPath);
Intent intent = new Intent();
intent.putExtra(&apk_path&, file.getPath());
setResult(RESULT_OK, intent);
public void onBackPressed() {
if (rootPath.equals(currentPath)) {
super.onBackPressed();
File file = new File(currentPath);
currentPath = file.getParentFile().getPath();
refreshListItems(currentPath);
这部分代码由于和我们本篇文件的主旨没什么关系,主要是为了方便demo展示的,因此我就不进行讲解了。
接下来修改MainActivity中的代码,如下所示:
* 仿360手机助手秒装和智能安装功能的主Activity。
public class MainActivity extends AppCompatActivity {
TextView apkPathT
String apkP
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apkPathText = (TextView) findViewById(R.id.apkPathText);
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
apkPath = data.getStringExtra(&apk_path&);
apkPathText.setText(apkPath);
public void onChooseApkFile(View view) {
Intent intent = new Intent(this, FileExplorerActivity.class);
startActivityForResult(intent, 0);
public void onSilentInstall(View view) {
if (!isRoot()) {
Toast.makeText(this, &没有ROOT权限,不能使用秒装&, Toast.LENGTH_SHORT).show();
if (TextUtils.isEmpty(apkPath)) {
Toast.makeText(this, &请选择安装包!&, Toast.LENGTH_SHORT).show();
final Button button = (Button)
button.setText(&安装中&);
new Thread(new Runnable() {
public void run() {
SilentInstall installHelper = new SilentInstall();
final boolean result = installHelper.install(apkPath);
runOnUiThread(new Runnable() {
public void run() {
if (result) {
Toast.makeText(MainActivity.this, &安装成功!&, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, &安装失败!&, Toast.LENGTH_SHORT).show();
button.setText(&秒装&);
}).start();
public void onForwardToAccessibility(View view) {
public void onSmartInstall(View view) {
* 判断手机是否拥有Root权限。
* @return 有root权限返回true,否则返回false。
public boolean isRoot() {
boolean bool =
bool = new File(&/system/bin/su&).exists() || new File(&/system/xbin/su&).exists();
} catch (Exception e) {
e.printStackTrace();
可以看到,在MainActivity中,我们对四个按钮点击事件的回调方法都进行了定义,当点击选择安装包按钮时就会调用onChooseApkFile()方法,当点击秒装按钮时就会调用onSilentInstall()方法。在onChooseApkFile()方法方法中,我们通过Intent打开了FileExplorerActivity,然后在onActivityResult()方法当中读取选择的apk文件路径。在onSilentInstall()方法当中,先判断设备是否ROOT,如果没有ROOT就直接return,然后判断安装包是否已选择,如果没有也直接return。接下来我们开启了一个线程来调用SilentInstall.install()方法,因为安装过程会比较耗时,如果不开线程的话主线程就会被卡住,不管安装成功还是失败,最后都会使用Toast来进行提示。
代码就这么多,最后我们来配置一下AndroidManifest.xml文件:
&?xml version=&1.0& encoding=&utf-8&?&
&manifest xmlns:android=&https://schemas.android.com/apk/res/android&
package=&com.example.installtest&&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE& /&
&application
android:allowBackup=&true&
android:icon=&@mipmap/ic_launcher&
android:label=&@string/app_name&
android:supportsRtl=&true&
android:theme=&@style/AppTheme&&
&activity android:name=&.MainActivity&&
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&category android:name=&android.intent.category.LAUNCHER& /&
&/intent-filter&
&/activity&
&activity android:name=&.FileExplorerActivity&/&
&/application&
&/manifest&
并没有什么特殊的地方,由于选择apk文件需要读取SD卡,因此在AndroidManifest.xml文件中要记得声明读SD卡权限。
另外还有一点需要注意,在Android 6.0系统中,读写SD卡权限被列为了危险权限,因此如果将程序的targetSdkVersion指定成了23则需要做专门的6.0适配,这里简单起见,我把targetSdkVersion指定成了22,因为6.0的适配工作也不在文章的讲解范围之内。
现在运行程序,就可以来试一试秒装功能了,切记手机一定要ROOT,效果如下图所示:
可以看到,这里我们选择的网易新闻安装包已成功安装到手机上了,并且没有弹出系统的安装界面,由此证明秒装功能已经成功实现了。
二、智能安装
那么对于ROOT过的手机,秒装功能确实可以避免弹出系统安装界面,在不影响用户操作的情况下实现静默安装,但是对于绝大部分没有ROOT的手机,这个功能是不可用的。那么我们应该怎么办呢?为此360手机助手提供了一种折中方案,就是借助Android提供的无障碍服务来实现智能安装。所谓的智能安装其实并不是真正意义上的静默安装,因为它还是要弹出系统安装界面的,只不过可以在安装界面当中释放用户的操作,由智能安装功能来模拟用户点击,安装完成之后自动关闭界面。这个功能是需要用户手动开启的,并且只支持Android 4.1之后的手机,如下图所示:
好的,那么接下来我们就模仿一下360手机助手,来实现类似的智能安装功能。
首先在res/xml目录下新建一个accessibility_service_config.xml文件,代码如下所示:
&accessibility-service xmlns:android=&https://schemas.android.com/apk/res/android&
android:packageNames=&com.android.packageinstaller&
android:description=&@string/accessibility_service_description&
android:accessibilityEventTypes=&typeAllMask&
android:accessibilityFlags=&flagDefault&
android:accessibilityFeedbackType=&feedbackGeneric&
android:canRetrieveWindowContent=&true&
其中,packageNames指定我们要监听哪个应用程序下的窗口活动,这里写com.android.packageinstaller表示监听Android系统的安装界面。description指定在无障碍服务当中显示给用户看的说明信息,上图中360手机助手的一大段内容就是在这里指定的。accessibilityEventTypes指定我们在监听窗口中可以模拟哪些事件,这里写typeAllMask表示所有的事件都能模拟。accessibilityFlags可以指定无障碍服务的一些附加参数,这里我们传默认值flagDefault就行。accessibilityFeedbackType指定无障碍服务的反馈方式,实际上无障碍服务这个功能是Android提供给一些残疾人士使用的,比如说盲人不方便使用手机,就可以借助无障碍服务配合语音反馈来操作手机,而我们其实是不需要反馈的,因此随便传一个值就可以,这里传入feedbackGeneric。最后canRetrieveWindowContent指定是否允许我们的程序读取窗口中的节点和内容,必须写true。
记得在string.xml文件中写一下description中指定的内容,如下所示:
&resources&
&string name=&app_name&&InstallTest&/string&
&string name=&accessibility_service_description&&智能安装服务,无需用户的任何操作就可以自动安装程序。&/string&
&/resources&
智能安装服务,无需用户的任何操作就可以自动安装程序。
接下来修改AndroidManifest.xml文件,在里面配置无障碍服务:
&?xml version=&1.0& encoding=&utf-8&?&
&manifest xmlns:android=&https://schemas.android.com/apk/res/android&
package=&com.example.installtest&&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE& /&
&application
android:allowBackup=&true&
android:icon=&@mipmap/ic_launcher&
android:label=&@string/app_name&
android:supportsRtl=&true&
android:theme=&@style/AppTheme&&
android:name=&.MyAccessibilityService&
android:label=&我的智能安装&
android:permission=&android.permission.BIND_ACCESSIBILITY_SERVICE&&
&intent-filter&
&action android:name=&android.accessibilityservice.AccessibilityService& /&
&/intent-filter&
&meta-data
android:name=&android.accessibilityservice&
android:resource=&@xml/accessibility_service_config& /&
&/service&
&/application&
&/manifest&
这部分配置的内容多数是固定的,必须要声明一个android.permission.BIND_ACCESSIBILITY_SERVICE的权限,且必须要有一个值为android.accessibilityservice.AccessibilityService的action,然后我们通过将刚才创建的配置文件指定进去。
接下来就是要去实现智能安装功能的具体逻辑了,创建一个MyAccessibilityService类并继承自AccessibilityService,代码如下所示:
* 智能安装功能的实现类。
public class MyAccessibilityService extends AccessibilityService {
Map handledMap = new HashMap&&();
public MyAccessibilityService() {
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo nodeInfo = event.getSource();
if (nodeInfo != null) {
int eventType = event.getEventType();
if (eventType== AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED ||
eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (handledMap.get(event.getWindowId()) == null) {
boolean handled = iterateNodesAndHandle(nodeInfo);
if (handled) {
handledMap.put(event.getWindowId(), true);
private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo != null) {
int childCount = nodeInfo.getChildCount();
if (&android.widget.Button&.equals(nodeInfo.getClassName())) {
String nodeContent = nodeInfo.getText().toString();
Log.d(&TAG&, &content is & + nodeContent);
if (&安装&.equals(nodeContent)
|| &完成&.equals(nodeContent)
|| &确定&.equals(nodeContent)) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else if (&android.widget.ScrollView&.equals(nodeInfo.getClassName())) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
for (int i = 0; i & childC i++) {
AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
if (iterateNodesAndHandle(childNodeInfo)) {
public void onInterrupt() {
代码并不复杂,我们来解析一下。每当窗口有活动时,就会有消息回调到onAccessibilityEvent()方法中,因此所有的逻辑都是从这里开始的。首先我们可以通过传入的AccessibilityEvent参数来获取当前事件的类型,事件的种类非常多,但是我们只需要监听TYPE_WINDOW_CONTENT_CHANGED和TYPE_WINDOW_STATE_CHANGED这两种事件就可以了,因为在整个安装过程中,这两个事件必定有一个会被触发。当然也有两个同时都被触发的可能,那么为了防止二次处理的情况,这里我们使用了一个Map来过滤掉重复事件。
接下来就是调用iterateNodesAndHandle()方法来去解析当前界面的节点了,这里我们通过递归的方式将安装界面中所有的子节点全部进行遍历,当发现按钮节点的时候就进行判断,按钮上的文字是不是&安装&、&完成&、&确定&这几种类型,如果是的话就模拟一下点击事件,这样也就相当于帮用户自动操作了这些按钮。另外从Android 4.4系统开始,用户需要将应用申请的所有权限看完才可以点击安装,因此如果我们在节点中发现了ScrollView,那就模拟一下滑动事件,将界面滑动到最底部,这样安装按钮就可以点击了。
最后,回到MainActivity中,来增加对智能安装功能的调用,如下所示:
* 仿360手机助手秒装和智能安装功能的主Activity。
public class MainActivity extends AppCompatActivity {
public void onForwardToAccessibility(View view) {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);
public void onSmartInstall(View view) {
if (TextUtils.isEmpty(apkPath)) {
Toast.makeText(this, &请选择安装包!&, Toast.LENGTH_SHORT).show();
Uri uri = Uri.fromFile(new File(apkPath));
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setDataAndType(uri, &application/vnd.android.package-archive&);
startActivity(localIntent);
当点击了开启智能安装服务按钮时,我们通过Intent跳转到系统的无障碍服务界面,在这里启动智能安装服务。当点击了智能安装按钮时,我们通过Intent跳转到系统的安装界面,之后所有的安装操作都会自动完成了。
现在可以重新运行一下程序,效果如下图所示:
可以看到,当打开网易新闻的安装界面之后,我们不需要进行任何的手动操作,界面的滑动、安装按钮、完成按钮的点击都是自动完成的,最终会自动回到手机原来的界面状态,这就是仿照360手机助手实现的智能安装功能。
好的,本篇文章的所有内容就到这里了,虽说不能说完全实现静默安装,但是我们已经在权限允许的范围内尽可能地去完成了,并且360手机助手也只能实现到这一步而已,那些被产品经理逼着去实现静默安装的程序员们也有理由交差了吧?

我要回帖

更多关于 儿童app界面 的文章

 

随机推荐