How to check the “Allow Full Access” is enabled in iOS 11? - ios

How to check the “Allow Full Access” is enabled in iOS 11?
I have tried multiple methods which do not seem to be working in iOS 10 or iOS 11.
Here is one that I tried:
func hasFullAccess() -> Bool
{
var hasFullAccess = false
if #available(iOSApplicationExtension 10.0, *) {
let pasty = UIPasteboard.general
if pasty.hasURLs || pasty.hasColors || pasty.hasStrings || pasty.hasImages {
hasFullAccess = true
} else {
pasty.string = "TEST"
if pasty.hasStrings {
hasFullAccess = true
pasty.string = ""
}
}
} else {
// Fallback on earlier versions
var clippy : UIPasteboard?
clippy = UIPasteboard.general
if clippy != nil {
hasFullAccess = true
}
}
return hasFullAccess
}
Every time it returns true and I am running this on a device not on the simulator.

First of all, it feels like you're checking the iOS version wrong. It usually looks like this if #available(iOS 11.0, *) where iOS version you pass is the latest one you use. In your declaration iOS 11 is not even there, it checks for iOS 10 and below.
Second, you're using || which is OR operator. So if any of those statements is true, the whole thing will return true. You need && the AND operator to check whether everything is matching.

Related

android 12 AudioManager.setCommunicationDevice not working

I'm building a voice call app for android using WebView. Everything works fine except in android 12, I can not use the earpiece (or even wired headphones in some phones) for audio out. The audio is always playing through loudspeaker. And some of the users reported that they can hear the internal ring(Which is a MediaPlayer object) in earpiece, but once the call answered it switches to loudspeaker. And the worst part is, I'm not able to reproduce this issue as this works perfectly on all my test phones (android 12).
My code,
private fun setAudioOutDevice(target: AudioDeviceInfo?) {
//need some delay for bluetooth sco
var audioChangeDelay: Long = 15
if (System.currentTimeMillis() - lastAudioChangeTime <= 300) audioChangeDelay = 300
Handler(Looper.getMainLooper()).postDelayed({
var targetDevice = target
//no device selected. scan all output devices and select one automatically
if (targetDevice == null) {
var wiredHeadsetDevice: AudioDeviceInfo? =
getAudioDevice(AudioDeviceInfo.TYPE_WIRED_HEADSET)
if (wiredHeadsetDevice == null) wiredHeadsetDevice =
getAudioDevice(AudioDeviceInfo.TYPE_WIRED_HEADPHONES)
val bluetoothDevice: AudioDeviceInfo? =
getAudioDevice(AudioDeviceInfo.TYPE_BLUETOOTH_SCO)
val speakerDevice: AudioDeviceInfo? =
getAudioDevice(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
val earpieceDevice: AudioDeviceInfo? =
getAudioDevice(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE)
//update global variables
isBluetoothAvailable = bluetoothDevice != null
//disable BT if wired headset connected
if (wiredHeadsetDevice != null) isBluetoothAvailable = false
//choose an output device
targetDevice =
if (callType == videoCall && bluetoothDevice == null && wiredHeadsetDevice == null) speakerDevice
else if (callType == videoCall && wiredHeadsetDevice == null && !isBluetoothAudioEnabled) speakerDevice
else wiredHeadsetDevice
?: if (isBluetoothAvailable && isBluetoothAudioEnabled && bluetoothDevice != null) bluetoothDevice
else earpieceDevice ?: speakerDevice
//no earpiece
if (earpieceDevice == null) {
setBigStatus("Unable to access Earpiece", 0)
}
}
//set output device
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
var success = false
try {
// am.clearCommunicationDevice()
if (targetDevice != null) success = am.setCommunicationDevice(targetDevice)
} catch (e: Exception) {
debugMsg(e.message.toString())
}
if (!success) setBigStatus(getString(R.string.unable_to_set_audio), 0)
}
//older devices, android 11 or lower
else {
am.mode = AudioManager.MODE_IN_COMMUNICATION
if (targetDevice?.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
changeSco(false)
am.isSpeakerphoneOn = true
} else {
if (targetDevice?.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) changeSco(true)
else changeSco(false)
am.isSpeakerphoneOn = false
}
}
}, audioChangeDelay)
}
private fun changeSco(enable: Boolean) {
if (enable) {
am.startBluetoothSco()
am.isBluetoothScoOn = true
} else {
am.stopBluetoothSco()
am.isBluetoothScoOn = false
}
}
private fun getAudioDevice(type: Int): AudioDeviceInfo? {
val audioDevices = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
for (deviceInfo in audioDevices) {
if (type == deviceInfo.type) return deviceInfo
}
return null
}
The above code is working fine on android 11 and lower and even on some android 12 phones. How can I make this work on all devices?
There is an issue tracker here. But it seems that nobody is working on it.
UPDATE Today I tried it on a pixel 3a and it gives mixed behaviors. Sometimes it plays on the earpiece or wired headset but for most of the calls, it plays on the loudspeaker only. And even if I don't set any mode, it automatically switches to MODE_IN_COMMUNICATION right after the stream starts. I think, android is trying to figure out the proper mode by itself and that messing with my app logic.

Swift if condition fails

Swift if statement works fine on all other devices but the iPhone 4S with iOS 9.2.1.
This is the set of code I am using:
I am printing a bool value above, before applying the condition, and it prints 0, but the compiler jumps directly to the else part, failing the if statement.
print(NSNumber.init(value: socketListener!.isConnected)) //prints 0
if socketListener!.isConnected == false {
// skipped
} else {
// executed
}
I would suggest you go the long, but the correct one, by unwrapping your socket listener optional, or you can even go directly with the long unwrapping:
guard let isConnected = socketListener.isConnected else { return }
print(NSNumber.init(value: isConnected)) //prints 0
if isConnected == false {
// Your code
} else {
// Your code
}

How to check the “Allow Full Access” is enabled in iOS 10?

How to check the “Allow Full Access” is enabled in iOS 10?
This method is not working in iOS 10
-(BOOL)isOpenAccessGranted{
return [UIPasteboard generalPasteboard];
}
Here's an objective c version
-(BOOL) checkIfFullAccessEnabled {
NSOperatingSystemVersion osv = [NSProcessInfo processInfo].operatingSystemVersion;
if(osv.majorVersion >= 10) {
UIPasteboard *pb = [UIPasteboard generalPasteboard];
if(pb.hasStrings || pb.hasURLs || pb.hasColors || pb.hasImages) {
return YES;
}
else {
NSString *ustr = pb.string;
pb.string = #"777-TEST-123";
if(pb.hasStrings) {
pb.string = ustr;
return YES;
}
else {
return NO;
}
}
}
else if([UIPasteboard generalPasteboard] != nil) {
return YES;
}
else {
return NO;
}
}
User #user979686 posted a solution in the following thread but I have not tested this.
https://stackoverflow.com/a/38903406/4792451
Posting the code here for clarity.
let originalString = UIPasteboard.general.string
UIPasteboard.general.string = "TEST"
if UIPasteboard.general.hasStrings
{
UIPasteboard.general.string = originalString
hasFullAccess = true
}
else
{
hasFullAccess = false
}
I've been testing this today and it appears that you don't have to set something on the pasteboard to verify that you have access. All you need to do is test to see if something is on the pasteboard. Of course if the pasteboard happens to be completely empty then it's not an exhaustive test so in that case you do need to set something, but then you've already ruled out anything being replaced. Here's what I came up with
func checkFullAccess() -> Bool
{
if #available(iOSApplicationExtension 10.0, *) {
let pasty = UIPasteboard.general
if pasty.hasURLs || pasty.hasColors || pasty.hasStrings || pasty.hasImages {
return true
} else {
pasty.string = "TEST"
if pasty.hasStrings {
pasty.string = ""
return true
}
}
} else {
// Fallback on earlier versions
var clippy : UIPasteboard?
clippy = UIPasteboard.general
return clippy != nil
}
return false
}
In my tests I found that all the checks (hasString, hasImages, etc) would return false even with content on the pasteboard with full access turned off. If they all return false then it could be truly empty so you try setting something in that case. If it wasn't empty then you don't have access and you won't be replacing anything, if it was empty and you do have access then the text will be placed there and you can return it to it's previous state.
HTH,
Mike

How can I detect if the currently running app was installed from the app store?

Is there a way in iOS to programmatically check if the currently running app was installed from the iOS App Store? This is in contrast to an app that was run via Xcode, TestFlight, or any non-official distribution source.
This is in the context of an SDK that doesn't have access to the app's source code.
To be clear - I am looking for some signature, so to speak, given to the app (presumably by Apple), that will, without dependence on any preprocessor flags or other build configurations, be accessible to any application at run time.
Apps downloaded from the App Store have a iTunesMetadata.plist file added by the store:
NSString *file=[NSHomeDirectory() stringByAppendingPathComponent:#"iTunesMetadata.plist"];
if ([[NSFileManager defaultManager] fileExistsAtPath:file]) {
// probably a store app
}
Perhaps you might want to check if this file exists.
Update:
In iOS8, the application bundle has been moved. According to #silyevsk, the plist is now one level above [the new application main bundle path], at /private/var/mobile/Containers/Bundle/Application/4A74359F-E6CD-44C9-925D-AC82E‌‌​​B5EA837/iTunesMetadata.plist, and unfortunately, this can't be accessed from the app (permission denied)
Update Nov 4th 2015:
It appears that checking the receipt name can help. It must be noted that this solution is slightly different: it doesn't return whether we're running an App Store app, but rather whether we're running a beta Testflight app. This might or might not be useful depending on your context.
On top of that, it's a very fragile solution because the receipt name could change at any time. I'm reporting it anyway, in case you have no other options:
// Objective-C
BOOL isRunningTestFlightBeta = [[[[NSBundle mainBundle] appStoreReceiptURL] lastPathComponent] isEqualToString:#"sandboxReceipt"];
// Swift
let isRunningTestFlightBeta = NSBundle.mainBundle().appStoreReceiptURL?.lastPathComponent=="sandboxReceipt"
Source: Detect if iOS App is Downloaded from Apple's Testflight
How HockeyKit does it
By combining the various checks you can guess whether the app is running in a Simulator, in a Testflight build, or in an AppStore build.
Here's a segment from HockeyKit:
BOOL bit_isAppStoreReceiptSandbox(void) {
#if TARGET_OS_SIMULATOR
return NO;
#else
NSURL *appStoreReceiptURL = NSBundle.mainBundle.appStoreReceiptURL;
NSString *appStoreReceiptLastComponent = appStoreReceiptURL.lastPathComponent;
BOOL isSandboxReceipt = [appStoreReceiptLastComponent isEqualToString:#"sandboxReceipt"];
return isSandboxReceipt;
#endif
}
BOOL bit_hasEmbeddedMobileProvision(void) {
BOOL hasEmbeddedMobileProvision = !![[NSBundle mainBundle] pathForResource:#"embedded" ofType:#"mobileprovision"];
return hasEmbeddedMobileProvision;
}
BOOL bit_isRunningInTestFlightEnvironment(void) {
#if TARGET_OS_SIMULATOR
return NO;
#else
if (bit_isAppStoreReceiptSandbox() && !bit_hasEmbeddedMobileProvision()) {
return YES;
}
return NO;
#endif
}
BOOL bit_isRunningInAppStoreEnvironment(void) {
#if TARGET_OS_SIMULATOR
return NO;
#else
if (bit_isAppStoreReceiptSandbox() || bit_hasEmbeddedMobileProvision()) {
return NO;
}
return YES;
#endif
}
BOOL bit_isRunningInAppExtension(void) {
static BOOL isRunningInAppExtension = NO;
static dispatch_once_t checkAppExtension;
dispatch_once(&checkAppExtension, ^{
isRunningInAppExtension = ([[[NSBundle mainBundle] executablePath] rangeOfString:#".appex/"].location != NSNotFound);
});
return isRunningInAppExtension;
}
Source: GitHub - bitstadium/HockeySDK-iOS - BITHockeyHelper.m
A possible Swift class, based on HockeyKit's class, could be:
//
// WhereAmIRunning.swift
// https://gist.github.com/mvarie/63455babc2d0480858da
//
// ### Detects whether we're running in a Simulator, TestFlight Beta or App Store build ###
//
// Based on https://github.com/bitstadium/HockeySDK-iOS/blob/develop/Classes/BITHockeyHelper.m
// Inspired by https://stackoverflow.com/questions/18282326/how-can-i-detect-if-the-currently-running-app-was-installed-from-the-app-store
// Created by marcantonio on 04/11/15.
//
import Foundation
class WhereAmIRunning {
// MARK: Public
func isRunningInTestFlightEnvironment() -> Bool{
if isSimulator() {
return false
} else {
if isAppStoreReceiptSandbox() && !hasEmbeddedMobileProvision() {
return true
} else {
return false
}
}
}
func isRunningInAppStoreEnvironment() -> Bool {
if isSimulator(){
return false
} else {
if isAppStoreReceiptSandbox() || hasEmbeddedMobileProvision() {
return false
} else {
return true
}
}
}
// MARK: Private
private func hasEmbeddedMobileProvision() -> Bool{
if let _ = NSBundle.mainBundle().pathForResource("embedded", ofType: "mobileprovision") {
return true
}
return false
}
private func isAppStoreReceiptSandbox() -> Bool {
if isSimulator() {
return false
} else {
if let appStoreReceiptURL = NSBundle.mainBundle().appStoreReceiptURL,
let appStoreReceiptLastComponent = appStoreReceiptURL.lastPathComponent
where appStoreReceiptLastComponent == "sandboxReceipt" {
return true
}
return false
}
}
private func isSimulator() -> Bool {
#if arch(i386) || arch(x86_64)
return true
#else
return false
#endif
}
}
Gist: GitHub - mvarie/WhereAmIRunning.swift
Update Dec 9th 2016:
User halileohalilei reports that "This no longer works with iOS10 and Xcode 8.". I didn't verify this, but please check the updated HockeyKit source (see function bit_currentAppEnvironment) at:
Source: GitHub - bitstadium/HockeySDK-iOS - BITHockeyHelper.m
Over time, the above class has been modified and it seems to handle iOS10 as well.
Update Oct 6th 2020:
Hockey has been deprecated/abandoned and replaced by Microsoft's AppCenter SDK.
This is their App Store / Testflight build detection class (link to repository below code):
MSUtility+Environment.h :
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSUtility.h"
/*
* Workaround for exporting symbols from category object files.
*/
extern NSString *MSUtilityEnvironmentCategory;
/**
* App environment
*/
typedef NS_ENUM(NSInteger, MSEnvironment) {
/**
* App has been downloaded from the AppStore.
*/
MSEnvironmentAppStore = 0,
/**
* App has been downloaded from TestFlight.
*/
MSEnvironmentTestFlight = 1,
/**
* App has been installed by some other mechanism.
* This could be Ad-Hoc, Enterprise, etc.
*/
MSEnvironmentOther = 99
};
/**
* Utility class that is used throughout the SDK.
* Environment part.
*/
#interface MSUtility (Environment)
/**
* Detect the environment that the app is running in.
*
* #return the MSEnvironment of the app.
*/
+ (MSEnvironment)currentAppEnvironment;
#end
MSUtility+Environment.m :
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "MSUtility+Environment.h"
/*
* Workaround for exporting symbols from category object files.
*/
NSString *MSUtilityEnvironmentCategory;
#implementation MSUtility (Environment)
+ (MSEnvironment)currentAppEnvironment {
#if TARGET_OS_SIMULATOR || TARGET_OS_OSX || TARGET_OS_MACCATALYST
return MSEnvironmentOther;
#else
// MobilePovision profiles are a clear indicator for Ad-Hoc distribution.
if ([self hasEmbeddedMobileProvision]) {
return MSEnvironmentOther;
}
/**
* TestFlight is only supported from iOS 8 onwards and as our deployment target is iOS 8, we don't have to do any checks for
* floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1).
*/
if ([self isAppStoreReceiptSandbox]) {
return MSEnvironmentTestFlight;
}
return MSEnvironmentAppStore;
#endif
}
+ (BOOL)hasEmbeddedMobileProvision {
BOOL hasEmbeddedMobileProvision = !![[NSBundle mainBundle] pathForResource:#"embedded" ofType:#"mobileprovision"];
return hasEmbeddedMobileProvision;
}
+ (BOOL)isAppStoreReceiptSandbox {
#if TARGET_OS_SIMULATOR
return NO;
#else
if (![NSBundle.mainBundle respondsToSelector:#selector(appStoreReceiptURL)]) {
return NO;
}
NSURL *appStoreReceiptURL = NSBundle.mainBundle.appStoreReceiptURL;
NSString *appStoreReceiptLastComponent = appStoreReceiptURL.lastPathComponent;
BOOL isSandboxReceipt = [appStoreReceiptLastComponent isEqualToString:#"sandboxReceipt"];
return isSandboxReceipt;
#endif
}
#end
Source: GitHub - microsoft/appcenter-sdk-apple - MSUtility+Environment.m
If you're talking about your own app, you could add a state that returns true if it was build as part of a Store version (e.g. a compiler conditional) and false in every other case.
If you're talking about another app, it's not easy or straightforward (or maybe not even possible) to query other apps outside of your sandbox.
Since the code by #magma no longer works IOS11.1 Here is a bit of a long winded solution.
We check the app version on the app store and compare it to the version in the Bundle
static func isAppStoreVersion(completion: #escaping (Bool?, Error?) -> Void) throws -> URLSessionDataTask {
guard let info = Bundle.main.infoDictionary,
let currentVersion = info["CFBundleShortVersionString"] as? String,
let identifier = info["CFBundleIdentifier"] as? String else {
throw VersionError.invalidBundleInfo
}
let urlString = "https://itunes.apple.com/gb/lookup?bundleId=\(identifier)"
guard let url = URL(string:urlString) else { throw VersionError.invalidBundleInfo }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
if let error = error { throw error }
guard let data = data else { throw VersionError.invalidResponse }
let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any]
guard let result = (json?["results"] as? [Any])?.first as? [String: Any], let appStoreVersion = result["version"] as? String else {
throw VersionError.invalidResponse
}
completion(appStoreVersion == currentVersion, nil)
} catch {
completion(nil, error)
}
}
task.resume()
return task
}
Called like this
DispatchQueue.global(qos: .background).async {
_ = try? VersionManager.isAppStoreVersion { (appStoreVersion, error) in
if let error = error {
print(error)
} else if let appStoreVersion = appStoreVersion, appStoreVersion == true {
// app store stuf
} else {
// other stuff
}
}
}
enum VersionError: Error {
case invalidResponse, invalidBundleInfo
}
My observation is when a device connected to Xcode, and then we open Organiser, switch to Devices pane it will list all Applications which is not installed from App Store. So what you have to do is download Xcode, then connect your device, go to Devices pane and see which all applications are installed from non-App Store sources. This is the simplest solution.

How to check for iOS5 using web technologies?

I'm working on a mobile app using jQuery Mobile and I would like to check if I'm on iOS5, cause it has some great features, like true fixed toolbars, etc. I'm looking for a javascript solution.
This works for me with a bit of string manipulation of the user-agent.
var ua = navigator.userAgent;
var detail = ua.split('(')[1];
var device = detail.split(';')[0];
if (device == 'iPhone' || device == 'iPod' || device == 'iPad') {
var ios = detail.split(' ')[5].split('_')[0];
if (ios == '5') {
alert('ios 5');
}
}

Resources