背景
从历史上看,Android自定义权限一直是一个混乱,并且依赖于安装顺序,这已知会暴露漏洞.
在API 21之前,有一个令人不安的解决方法,即在您的Manifest中声明另一个应用程序的自定义权限,授予权限......但是,自API 21以来,只有一个应用程序可以声明自定义权限并安装另一个应用程序声明同样的许可,将被阻止.
替代方案是重新安装需要许可的应用程序,因此系统会检测到它们,但这不是一个好的用户体验.或者在运行时检查调用应用程序的权限,但这并非没有理论上的缺陷.
问题
从Android Marshmallow(6.0 - API 23)开始,应用程序需要请求用户的许可,才能使用自己的自定义权限.未自动授予声明的自定义权限.
这似乎很奇怪,因为现在只有一个应用程序可以声明它.
要复制
在Manifest中声明自定义权限和BroadcastReceiver.
<permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
android:description="@string/control_description"
android:icon="@mipmap/ic_launcher"
android:label="@string/control_label"
android:protectionLevel="normal or dangerous"/>
<uses-permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
// etc
<receiver
android:name="com.example.app.MyBroadcastReceiver"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
<intent-filter android:priority="999">
<action android:name="com.example.app.REQUEST_RECEIVER"/>
</intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)
从第三方应用程序,声明它使用Manifest中的自定义权限(并通过对话框或设置接受它)并调用:
final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// getResultCode();
}
}, null, Activity.RESULT_CANCELED, null, null); …Run Code Online (Sandbox Code Playgroud) 我正在开发一个基于语音识别的Android应用程序.
直到今天,一切都工作得很好并且及时,例如,我会开始我的语音识别器,说话,并且在最多1或2秒内,应用程序收到结果.
这是一个非常可接受的用户体验.
那么今天我现在必须等待十秒或更长时间才能获得识别结果.
我尝试过设置以下EXTRAS,其中没有一个会产生任何明显的区别
RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS
Run Code Online (Sandbox Code Playgroud)
我一直在不断更改我的应用程序,但这些更改都与语音识别器无关.
我可以采用任何方法来缩短语音识别器切换onBeginningOfSpeech()到的时间onResults()吗?
这是一个需要多长时间的例子
07-01 17:50:20.839 24877-24877/com.voice I/Voice: onReadyForSpeech()
07-01 17:50:21.614 24877-24877/com.voice I/Voice: onBeginningOfSpeech()
07-01 17:50:38.163 24877-24877/com.voice I/Voice: onEndOfSpeech()
Run Code Online (Sandbox Code Playgroud) android speech-recognition voice-recognition google-voice-search
我有一个远程服务,外部应用程序可以绑定到该服务.在某些情况下,我可能希望拒绝绑定.根据文件,
将通信通道返回给服务.如果客户端无法绑定到服务,则可能返回null.
@Override
public IBinder onBind(final Intent intent) {
return null;
}
Run Code Online (Sandbox Code Playgroud)
返回null确实不会返回IBinder对象,因此会阻止连接,但是调用应用程序无法正确接收此"信息".
boolean bound = context.bindService(intent, serviceConnection, flagsHere);
Run Code Online (Sandbox Code Playgroud)
无论是否从服务返回null,这总是返回true?
根据文件,
返回 - 如果已成功绑定到服务,则返回true; 如果未建立连接,则返回false,因此您将不会收到服务对象
我曾假设从onBind返回null 会导致bindService返回false.假设永远不是一个好主意......
但是,返回null确实会阻止ServiceConnection被实例化调用,但是这样做的结果就是没有选项来检查绑定在onServiceConnected中是否实际为null .
所以,我的问题 - 如果绑定请求被拒绝,应用程序如何"知道"?
另外,如果我在飞行中决定对onRebind(先前从onUnbind返回true )的请求应该被拒绝,我似乎无法覆盖行为以防止这种情况:
@Override
public void onRebind(final Intent intent) {
if (shouldAllowRebind(intent)) {
super.onRebind(intent);
} else {
// ?
}
}
Run Code Online (Sandbox Code Playgroud)
我希望有人可以为我解释一下.提前致谢.
我有以下父方法,在所有情况下都使用各种API级别:
public int setVoice (@NonNull final String language, @NonNull final String region){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return setVoice21(language, region);
} else {
return setVoiceDeprecated(language, region);
}
}
Run Code Online (Sandbox Code Playgroud)
并setVoice21做这样的事情:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public int setVoice21 ( @NonNull final String language, @NonNull final String region){
try {
// try some API 21 stuff
} catch (final IllformedLocaleException e) {
e.printStackTrace();
return setVoiceDeprecated(language, region);
}
Run Code Online (Sandbox Code Playgroud)
setVoice21包含其他需要API 21+的代码,特别是TextToSpeech.Voice和Locale.Builder
当我在设备<API 21上运行此代码时,我收到以下错误:
W/dalvikvm:VFY:无法解析异常类6232(Ljava/util/IllformedLocaleException;)W/dalvikvm:VFY:拒绝操作码0x0d在0x0168 W/dalvikvm:VFY:拒绝Lcom/myapp/android/speech/MyTextToSpeech; .setVoice21 (Ljava/lang/String; Ljava/lang/String;)IW/dalvikvm:Verifier拒绝了类Lcom/myapp/android/speech/MyTextToSpeech;
E/AndroidRuntime:FATAL EXCEPTION:main java.lang.VerifyError:com/myapp/android/speech/MyTextToSpeech
如果我删除了 …
由于这种恼人的Android限制,我需要用户重新安装我的应用程序,以便其他应用程序检测到清单权限.
这对用户来说已经是令人沮丧的了,但另外,我看不到从/ data/app中存储的apk重新安装我的应用程序的方法,因此我必须将相同的版本下载到存储卡才能解雇通常的安装意图.
我急切地等着有人告诉我,我错过了一些明显的东西!我画了一个空白......
提前致谢.
如果您希望解决问题,请为问题加注星标!干杯.
编辑:考虑到@hackbod的注释,您可以使用以下代码启动安装对话框.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(this.getApplicationInfo().sourceDir)),
"application/vnd.android.package-archive");
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)
在我的Jelly Bean设备上,它提供了两个选项:包安装程序和验证并安装.我不知道后者是否会处理以下问题:
我的申请是免费的,所以我无法测试以下的付费问题:
虽然hackbod完成了"其他人可读",这表明如果您通过自己的代码执行此操作,对于您自己的应用程序,它是可读的吗?如果你可以测试一下,请纠正我,我错了.
对于极少数用户来说,我面临着一个非常令人困惑的问题.在Fragment中按下按钮时会发生错误,该按钮会启动另一个Fragment Activity.这是堆栈跟踪:
I/20:22:23.901 ActivityManager( 1668)
Start proc com.brandall.nutter for activity com.brandall.nutter/.ActivityHomeFragment: pid=8956 uid=10125 gids={50125, 3003, 3001, 3002, 1015, 1023, 1006, 1028}
I/20:22:23.881 WindowState( 1668)
WIN DEATH: Window{41ed1948 u0 com.brandall.nutter/com.brandall.nutter.ActivityLinkAppsFragment}
W/20:22:23.881 ActivityManager( 1668)
Force removing ActivityRecord{411c4188 u0 com.brandall.nutter/.ActivityLinkAppsFragment}: app died, no saved state
I/20:22:23.881 WindowState( 1668)
WIN DEATH: Window{41b6a178 u0 Toast EXITING}
W/20:22:23.881 InputDispatcher( 1668)
Attempted to unregister already unregistered input channel '41ed1948 com.brandall.nutter/com.brandall.nutter.ActivityLinkAppsFragment (server)'
W/20:22:23.871 ActivityManager( 1668)
Scheduling restart of crashed service com.brandall.nutter/.TTSS in 80000ms
I/20:22:23.871 ActivityManager( 1668)
Process com.brandall.nutter …Run Code Online (Sandbox Code Playgroud) 在大多数Android设备中,RecognitionService将由Google的原生"现在/助理"应用程序提供.
在Android Oreo之前,我能够使用以下简单代码查询Google Recognizer支持的语言:
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
// vrIntent.setPackage("com.google.android.googlequicksearchbox");
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// final Bundle bundle = intent.getExtras();
final Bundle bundle = getResultExtras(true);
if (bundle != null) {
if (bundle.containsKey(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES)) {
Log.i("TAG", "onReceive: EXTRA_SUPPORTED_LANGUAGES present");
final ArrayList<String> vrStringLocales = bundle.getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
Log.i("TAG", "onReceive: EXTRA_SUPPORTED_LANGUAGES size: " + vrStringLocales.size());
} else {
Log.w("TAG", "onReceive: missing EXTRA_SUPPORTED_LANGUAGES");
}
} else {
Log.w("TAG", "onReceive: Bundle null"); …Run Code Online (Sandbox Code Playgroud) java android speech-recognition voice-recognition google-voice-search
App A定义了以下的自定义权限:
com.package.permission.READ_APP_DATA
Run Code Online (Sandbox Code Playgroud)
当安装应用程序B声明自定义权限时,它将被授予.
但是,如果在应用B之后安装了应用A,则该权限不会授予应用B.
虽然这可能不常见,但由于应用程序B经常是应用程序A的插件,它当然可以发生并且适用于我的应用程序.
android.permission.ACCESS_SUPERUSER如果用户决定切换SuperUser应用程序,SuperUser应用程序同意引入全局自定义权限可能是一个大问题.
为了处理这个问题,我打算在我的应用程序中使用以下代码来获取我即将开始声明的自定义权限:
checkPermissions(this, getCallingActivity().getPackageName()); // get the package name from the sender first
private boolean checkPermissions(Context context, String callingPackage) {
final List<PackageInfo> apps = context.getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS);
for (PackageInfo pi : apps) {
if (pi.packageName.equals(callingPackage)) {
String[] permissions = pi.requestedPermissions;
if (permissions != null) {
for (String permission : permissions) {
if (permission.equals("com.package.permission.READ_APP_DATA")) {
return true;
}
}
}
}
}
return false;
Run Code Online (Sandbox Code Playgroud)
根据这个问题的标题:这种方法"安全"吗?或者是否有一种方法/ root-hack,应用程序的清单在安装后可以更改,并且以编程方式"添加"到应用程序B的权限?
我有一个前台服务通知,点击后应该开始一个活动.这个活动在调用finish()之前很短暂.
第一次单击通知时,它会工作,第二次,然后我收到错误:
Sending contentIntent failed: android.app.PendingIntent$CanceledException
Run Code Online (Sandbox Code Playgroud)
在创建前台服务通知的代码中,我将randomActivity.class更改为另一个不调用finish的Activity类,它在每次单击时都能正常工作.从:
Intent notificationIntent = new Intent(this, RandomActivity.class);
Run Code Online (Sandbox Code Playgroud)
至:
Intent notificationIntent = new Intent(this, HomeActivity.class);
Run Code Online (Sandbox Code Playgroud)
工作良好...
我使用了Android开发者网站上的标准通知代码,并使用"通知"构建器对其进行了测试.无论如何我得到相同的结果.它完美地工作,除非Activity调用finish();
这是预期的行为,一个错误,还是我错过了什么?
我提前感谢你的帮助,希望能有一个解决方案!
注意:我使用的通知代码是完全标准的,所以我没有发布它.RandomActivity调用finish(); 在onCreate,所以也没有什么不寻常的.
我的用户SkuType.INAPP已从我的应用程序中购买了items().
在前面推荐的在应用程序内结算的实施中IabHelper.QueryInventoryFinishedListener会返回一个Inventory包含任何项目,他们所拥有.
在新的Play Billing Library中,我使用以下方法:
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
Run Code Online (Sandbox Code Playgroud)
假设响应代码成功,我查询:
purchasesResult.getPurchasesList()
Run Code Online (Sandbox Code Playgroud)
对于这一小部分用户,列表为空.
作为故障保护,对于上面的否定结果,我继续尝试:
mBillingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, this);
Run Code Online (Sandbox Code Playgroud)
该 onPurchaseHistoryResponse(final int responseCode, final List<Purchase> purchasesList)
成功详细购买.
对此感到困惑,我要求运行这两个实现的受影响用户确认以下内容:
根据这个帖子的建议,我让他们:
尽管如此,仍然只能queryPurchaseHistoryAsync正确识别他们的帐户拥有的项目.
问题:为什么?
该结算图书馆实现状态:
queryPurchaseHistoryAsync()返回用户为每个SKU进行的最新购买,即使该购买已过期,取消或已消耗.尽可能使用queryPurchases()方法,因为它使用本地缓存,而不是queryPurchaseHistoryAsync()方法.
我已在订单管理中确认购买有效且尚未取消.我不消耗它们,因此它们不能过期.
现在我有一个问题
鉴于对于这些用户我只能以上述方式识别他们的购买,我被迫为所有人实现这种故障保护.
除了因为必须这样做而感到沮丧之外,在您再次阅读之前,这似乎不是太大的问题:
queryPurchaseHistoryAsync()返回用户为每个SKU进行的最新购买,即使该购买已过期,取消或已消耗
因此,在我的标准实施中,我需要检查此购买是否仍然有效.
不幸的是,Purchase对象没有这样的方法来检查其有效性.
所以,我可能需要进行外部检查 …
android in-app-purchase in-app-billing android-billing play-billing-library