How BarAlarm iOS app is made? [duplicate] - objective-c

I am developing a non-appstore app for iOS. I want to read the cellular signal strength in my code.
I know Apple doesn't provide any API by which we can achieve this.
Is there any private API that can be used to achieve this? I have gone through the various threads regarding this issue but could not find any relevant info.
It is completely possible because there is an app in the app-store for detecting the carrier's signal strength.

Get signalStreght IOS9:
UIApplication *app = [UIApplication sharedApplication];
NSArray *subviews = [[[app valueForKey:#"statusBar"] valueForKey:#"foregroundView"] subviews];
NSString *dataNetworkItemView = nil;
for (id subview in subviews) {
if([subview isKindOfClass:[NSClassFromString(#"UIStatusBarSignalStrengthItemView") class]])
{
dataNetworkItemView = subview;
break;
}
}
int signalStrength = [[dataNetworkItemView valueForKey:#"signalStrengthRaw"] intValue];
NSLog(#"signal %d", signalStrength);

It is not very hard.
Link CoreTelephony.framework in your Xcode project
Add the following lines where you need it
Code:
int CTGetSignalStrength(); // private method (not in the header) of Core Telephony
- (void)aScanMethod
{
NSLog(#"%d", CTGetSignalStrength()); // or do what you want
}
And you are done.
Update May 2016
Apple removed this opportunity.

I briefly looked at the VAFieldTest project located at Github.
There seems to be getSignalStrength() and register_notification() functions in Classes/VAFieldTestViewController.m that might be interesting to you as they call into CoreTelephony.framework.
I am pretty confident that some of the used calls are undocumented in the CoreTelephony framework documentation from Apple and therefore private - any app in the AppStore must have slipped passed inspection.

To get signal streght in iOS 9 or above in Swift 3, without using the private API from CoreTelephony - CTGetSignalStrength(). Just scouring the statusBar view.
func getSignalStrength() -> Int {
let application = UIApplication.shared
let statusBarView = application.value(forKey: "statusBar") as! UIView
let foregroundView = statusBarView.value(forKey: "foregroundView") as! UIView
let foregroundViewSubviews = foregroundView.subviews
var dataNetworkItemView:UIView!
for subview in foregroundViewSubviews {
if subview.isKind(of: NSClassFromString("UIStatusBarSignalStrengthItemView")!) {
dataNetworkItemView = subview
break
} else {
return 0 //NO SERVICE
}
}
return dataNetworkItemView.value(forKey: "signalStrengthBars") as! Int
}
Attention: If the status bar is hidden, the key "statusBar" will return nil.

I haven't tested it, but apparently this is now a method of CTTelephonyNetworkInfo instead of a global/static function.
The return type is id, so I think you get either a NSDictionary (as the _cachedSignalStrength ivar implies) or an NSNumber (as the old function implies).
id signalStrength = [[CTTelephonyNetworkInfo new] signalStrength];
This changed in iOS 8.3, as you can see from the commit.
Note that this is still not documented! So if your app will go in the App Store, take your precautions.

Here's Lucas' answer converted to Xamarin, and tested on iOS 10.2.1:
var application = UIApplication.SharedApplication;
var statusBarView = application.ValueForKey(new NSString("statusBar")) as UIView;
var foregroundView = statusBarView.ValueForKey(new NSString("foregroundView")) as UIView;
UIView dataNetworkItemView = null;
foreach (UIView subview in foregroundView.Subviews)
{
if ("UIStatusBarSignalStrengthItemView" == subview.Class.Name)
{
dataNetworkItemView = subview;
break;
}
}
if (null == dataNetworkItemView)
return false; //NO SERVICE
int bars = ((NSNumber)dataNetworkItemView.ValueForKey(new NSString("signalStrengthBars"))).Int32Value;

Related

How to get the Ad Unit ID in Rewarded Video AdMob callbacks in Objective-C

We're developing an iOS app in objective-C and we've decided to add Firebase in our app. We also decided to add the GoogleMobileAds framework that comes with it in order to have Rewarded Video Ads.
I've implemented AdMob as detailed in the official guide but I can't figure out how to get the ad unit ID in each of the callbacks.
The only parameter I have is of type GADRewardBasedVideoAd and it doesn't seem to have any accessible data that provide the ad ID.
Here's one of the callbacks:
- (void)rewardBasedVideoAdDidOpen:(GADRewardBasedVideoAd *)rewardBasedVideoAd
{
NSLog(#"Opened reward based video ad.");
}
I need the ad ID because we're using several ads in our app and I need to know which one is ready/opened/completed/failed/etc.
I tried to use rewardBasedVideoAd.adMetadata[#"AdId"] but it returns nil.
Any help would be appreciated.
Thanks
here:
#implementation GameViewController{
GADRewardedAd *gameOverRewardedAd, *extraCoinsRewardedAd;
}
-(void)viewDidLoad{
gameOverRewardedAd = [self createAndLoadRewardedAdForAdUnit:#"ca-app-pub-YOURID"];
extraCoinsRewardedAd = [self createAndLoadRewardedAdForAdUnit:#"ca-app-pub-YOURID"];
}
-(GADRewardedAd *)createAndLoadRewardedAdForAdUnit:(NSString *) adUnitId {
GADRewardedAd *rewardedAd = [[GADRewardedAd alloc] initWithAdUnitID:adUnitId];
GADRequest *request = [GADRequest request];
[rewardedAd loadRequest:request completionHandler:^(GADRequestError * _Nullable error) {
if (error) {
// Handle ad failed to load case.
} else {
// Ad successfully loaded.
}
}];
return rewardedAd;
}
Then:
#pragma mark admob reward Ad delegate
- (void)rewardedAdDidDismiss:(GADRewardedAd *)rewardedAd {
//NSLog(#"rewardedAdDidDismiss:");
if (rewardedAd == gameOverRewardedAd) {
//do your things here
}else if (rewardedAd == extraCoinsRewardedAd){
}
}
Hope this helps.

app broke after Xcode update

I have a Swift app, with some Objective-C code mixed in. It was working yesterday, but this morning I updated XCode and now everything had gone to hell!
Firstly, after updating, I clicked the XCode popup box to allow it to upgrade my app to Swift4. This is where the problems started.
I have a Swift class called RestClient with the following 4 functions (among others):
class func getInstance() -> RestClient {
if (gRestClient == nil) {
let prefs:UserDefaults = UserDefaults.standard
return RestClient(username: prefs.string(forKey: "username")!, password: prefs.string(forKey: "password")!)
}
return gRestClient!
}
class func getUsername() -> String {
if (gUsername == nil) {
let prefs:UserDefaults = UserDefaults.standard
gUsername = prefs.string(forKey: "username")!
}
return gUsername!
}
class func getPassword() -> String {
if (gPassword == nil) {
let prefs:UserDefaults = UserDefaults.standard
gPassword = prefs.string(forKey: "password")!
}
return gPassword!
}
public func getServer() -> String {
return MAIN_SERVER;
}
Then in my /Objective-C/ folder, I have some more files, once of which is called RestClientObj.m. In here, I have this lines of code:
NSString* url = [NSString stringWithFormat:#"%#/receipt/email/%#/%#/", [[RestClient getInstance] getServer], rrn, emailAddress];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", [RestClient getUsername], [RestClient getPassword]];
So as you can see, I'm calling the RestClient.swift from here. The RestClientObj.h is as follows:
#ifndef RestClientObj_h
#define RestClientObj_h
#endif /* ResClientObj_h */
#interface RestClientObj : NSObject {
}
+(BOOL) sendSMS:(NSString *)rrn mn:(NSString *)mobileNumber;
+(BOOL) sendEmail:(NSString *)rrn mn:(NSString *)emailAddress;
#end
This whole upgrade is causing other problems too. I have another class with the following error:
No visible #interface for 'AppDelegate' declares the selector 'managedObjectContext'
on the line:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext]; <-ERROR
Can anyone shed any light on this?
EDIT: Here's some code from the AppDelegate class:
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
Just to close this off.
The issue was missing the #obj identifier before the variable declaration to make it visible to my objective-c code, in combination with the XCode Swift Upgrade wizard renaming some functions.

FinderSync Extension - requestBadgeIdentifierForURL is never called

I have tested the template provided in Xcode for making a FinderSync Extension. Everything works well except two things:
a) The method requestBadgeIdentifierForURL is never called by the system when a folder is monitored so that badges are not set. What is going wrong here? I am right assuming that this method should be called when I e.g. move or scroll a monitored folder in Finder? By the way the methods beginObservingDirectoryAtURL and endObservingDirectoryAtURL are called properly in this context.
#import "FinderSync.h"
#interface FinderSync ()
#property NSURL *myFolderURL;
#end
#implementation FinderSync
- (instancetype)init {
self = [super init];
NSLog(#"%s launched from %# ; compiled at %s", __PRETTY_FUNCTION__, [[NSBundle mainBundle] bundlePath], __TIME__);
// Set up the directory we are syncing.
self.myFolderURL = [NSURL fileURLWithPath:#"/Users/hmaass/Downloads"];
[FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:self.myFolderURL];
// Set up images for our badge identifiers. For demonstration purposes, this uses off-the-shelf images.
[[FIFinderSyncController defaultController] setBadgeImage:[NSImage imageNamed: NSImageNameColorPanel] label:#"Status One" forBadgeIdentifier:#"One"];
[[FIFinderSyncController defaultController] setBadgeImage:[NSImage imageNamed: NSImageNameCaution] label:#"Status Two" forBadgeIdentifier:#"Two"];
return self;
}
#pragma mark - Primary Finder Sync protocol methods
- (void)beginObservingDirectoryAtURL:(NSURL *)url {
// The user is now seeing the container's contents.
// If they see it in more than one view at a time, we're only told once.
NSLog(#"beginObservingDirectoryAtURL:%#", url.filePathURL);
}
- (void)endObservingDirectoryAtURL:(NSURL *)url {
// The user is no longer seeing the container's contents.
NSLog(#"endObservingDirectoryAtURL:%#", url.filePathURL);
}
- (void)requestBadgeIdentifierForURL:(NSURL *)url {
NSLog(#"requestBadgeIdentifierForURL:%#", url.filePathURL);
// For demonstration purposes, this picks one of our two badges, or no badge at all, based on the filename.
NSInteger whichBadge = [url.filePathURL hash] % 3;
NSString* badgeIdentifier = #[#"", #"One", #"Two"][whichBadge];
[[FIFinderSyncController defaultController] setBadgeIdentifier:badgeIdentifier forURL:url];
}
#pragma mark - Menu and toolbar item support
- (NSString *)toolbarItemName {
return #"testfifi";
}
- (NSString *)toolbarItemToolTip {
return #"testfifi: Click the toolbar item for a menu.";
}
- (NSImage *)toolbarItemImage {
return [NSImage imageNamed:NSImageNameCaution];
}
- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
// Produce a menu for the extension.
NSMenu *menu = [[NSMenu alloc] initWithTitle:#""];
[menu addItemWithTitle:#"Example Menu Item" action:#selector(sampleAction:) keyEquivalent:#""];
return menu;
}
- (IBAction)sampleAction:(id)sender {
NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];
NSLog(#"sampleAction: menu item: %#, target = %#, items = ", [sender title], [target filePathURL]);
[items enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#" %#", [obj filePathURL]);
}];
}
#end
b) I get the following message in the log console of Xcode when running the template above:
2015-08-25 15:33:00.300 testfifi[855:8134] Failed to connect
(colorGridView) outlet from (NSApplication) to
(NSColorPickerGridView): missing setter or instance variable
2015-08-25 15:33:00.300 testfifi[855:8134] Failed to connect (view)
outlet from (NSApplication) to (NSColorPickerGridView): missing setter
or instance variable 2015-08-25 15:33:00.321 testfifi[855:8134]
-[FinderSync init] launched from /Users/hmaass/Library/Developer/Xcode/DerivedData/testtest-egudnxkifjxirpbrjkohnatmjuro/Build/Products/Debug/testtest.app/Contents/PlugIns/testfifi.appex
; compiled at 20:38:18
Can someone help me to get rid of this message?
Thanks!
I already commented on your question but figured I should post a more complete answer.
It sounds like the issue you're having is another Finder Sync extension is "greedily" observing all folders, most likely the Dropbox Finder Integration. Try disabling all other Finder Sync extensions (under System Preferences -> Extensions -> Finder) and re-run your test.
If this resolves the issue, the problem is that Dropbox (or another app) has already called beginObservingDirectoryAtURL for the folder you're trying to monitor. Unfortunately, Apple's API is lacking in that there is no intelligent logic to who gets to monitor a folder when there are conflicting extensions. Currently, whichever Finder Sync extension starts first will "win".
Dropbox greedily monitors all folders under the user's home directory. I've written to both Apple and Dropbox to address this, but haven't heard any response. Currently, the (ugly) workaround I've implemented is to shutdown known "greedy" extensions, start my own extension, then restart the greedy extension.
Here's the workaround sample code for disabling "greedy" Finder Sync extensions. Nothing fancy, but it works.
(Adding this as a separate answer since it's really just a workaround and isn't necessarily the "correct" answer).
public static void main(String[] args) throws Exception {
String[] greedyFSProcessNames =
new String[] { "com.getdropbox.dropbox.garcon" };
List<String> disabledGreedyFSProcessNames = new ArrayList<>();
for (String greedyFSProcessName : greedyFSProcessNames) {
if (!_isFSProcessRunning(greedyFSProcessName)) {
continue;
}
_enableFSProcess(greedyFSProcessName, false);
disabledGreedyFSProcessNames.add(greedyFSProcessName);
}
_enableFSProcess("com.dejuknow.myfindersync", true);
for (String disabledGreedyFSProcessName :
disabledGreedyFSProcessNames) {
_enableFSProcess(disabledGreedyFSProcessName, true);
}
}
private static boolean _isFSProcessRunning(String processName)
throws Exception {
BufferedReader bufferedReader = null;
try {
Process process = Runtime.getRuntime().exec(
"pluginkit -m -i" + processName);
bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
if (line.startsWith("+")) {
return true;
}
else {
return false;
}
}
}
finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
return false;
}
private static void _enableFSProcess(String processName, boolean enable)
throws Exception {
String electionArgument = null;
if (enable) {
electionArgument = "use";
}
else {
electionArgument = "ignore";
}
String[] arguments = new String[] {
"pluginkit", "-e", electionArgument, "-i", processName
};
while (_isFSProcessRunning(processName) != enable) {
Process process = Runtime.getRuntime().exec(arguments);
process.waitFor();
Thread.sleep(100);
}
}
The folders I know Dropbox uses: ~/Dropbox, ~/Documents and ~/Desktop.
I have a FinderSync app too and I can display badges on all of my folders except those. Fortunately the context menu does not seem to suffer any conflict, both extension's menu items are shown.

WKWebKit Mac OS NSPrintOperation

WebKit 1 exposed the WebFrameView where I could call a print operation.
- (void)webView:(WebView *)sender printFrameView:(WebFrameView *)frameView {
NSPrintOperation *printOperation = [frameView printOperationWithPrintInfo:[NSPrintInfo sharedPrintInfo]];
[printOperation runOperation];
}
With WKWebKit API I can't seem to figure out how to perform a similar action or which view to grab for printing. All my efforts have come up with blank pages.
macOS 11 update: the printOperation(with:) method is no longer private and is now the solution that I use in my apps.
Amazingly, WKWebView still doesn't support printing on macOS, despite the legacy WebView being deprecated.
Looking at https://github.com/WebKit/webkit/commit/0dfc67a174b79a8a401cf6f60c02150ba27334e5 , printing was implemented years ago as a private API, but for some reason, has not been exposed. If you don't mind using a private API, you can print a WKWebView with:
public extension WKWebView {
// standard printing doesn't work for WKWebView; see http://www.openradar.me/23649229 and https://bugs.webkit.org/show_bug.cgi?id=151276
#available(OSX, deprecated: 10.16, message: "WKWebView printing will hopefully get fixed someday – maybe in 10.16?")
private static let webViewPrintSelector = Selector(("_printOperationWithPrintInfo:")) // https://github.com/WebKit/webkit/commit/0dfc67a174b79a8a401cf6f60c02150ba27334e5
func webViewPrintOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) -> NSPrintOperation? {
guard self.responds(to: Self.webViewPrintSelector) else {
return nil
}
guard let po: NSPrintOperation = self.perform(Self.webViewPrintSelector, with: NSPrintInfo(dictionary: printSettings))?.takeUnretainedValue() as? NSPrintOperation else {
return nil
}
// without initializing the print view's frame we get the breakpoint at AppKitBreakInDebugger:
// ERROR: The NSPrintOperation view's frame was not initialized properly before knowsPageRange: returned. This will fail in a future release! (WKPrintingView)
po.view?.frame = self.bounds
return po
}
}
You can have this be the default print operation for your NSDocument subclass by adding:
override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation {
return myWebView.webViewPrintOperation(withSettings: printSettings) ?? try super.printOperation(withSettings: printSettings)
}
Here is marcprux swift solution in Objective C:
SEL printSelector = NSSelectorFromString(#"_printOperationWithPrintInfo:");
if ([self.webView respondsToSelector:printSelector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSPrintOperation *printOperation = (NSPrintOperation*) [self.webView performSelector:printSelector withObject:[NSPrintInfo sharedPrintInfo]];
#pragma clang diagnostic pop
return printOperation;
}
Starting on macOS 11 this is not private anymore: printOperation(with:)
Usage:
let info = NSPrintInfo.shared
// configure info...
let operation = webView.printOperation(with: info)

UISwitches, need an explanation

How do the switches work in XCode4? how do i check which properties are available to me for the switches?
i am trying to check the state of a switch and make a label change according to the state. Something like this:
-(IBAction)clickedOnSwitch:(id)sender {
NSString *switchState = [[NSString alloc]init];
if (mySwitchIsOn) {
switchState = #"switch is On";
}
else
{
switchState = #"switch is Off";
}
myLabel.text = switchState;
[switchState release];
}
Take a look at the UISwitch class reference either on the web or in the Xcode documentation browser.