v11: encode wiederhergestellt, Absturz-Melder, Methoden-Check
This commit is contained in:
1 parent
b85fe90c38
commit
98a94e765e
5 files changed
+89
-5
No files matched your search
@@ -28,7 +28,6 @@
|
|||||||
65AABC92308B81050050A7AC /* GuidanceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC90308B81050050A7AC /* GuidanceManager.m */; };
|
65AABC92308B81050050A7AC /* GuidanceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC90308B81050050A7AC /* GuidanceManager.m */; };
|
||||||
65AABC98308B83BE0050A7AC /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC94308B83BE0050A7AC /* SettingsViewController.m */; };
|
65AABC98308B83BE0050A7AC /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC94308B83BE0050A7AC /* SettingsViewController.m */; };
|
||||||
65AABC99308B83BE0050A7AC /* BVGSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC95308B83BE0050A7AC /* BVGSettings.m */; };
|
65AABC99308B83BE0050A7AC /* BVGSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC95308B83BE0050A7AC /* BVGSettings.m */; };
|
||||||
65AABC9C308B87630050A7AC /* AppIcon.appiconset in Resources */ = {isa = PBXBuildFile; fileRef = 65AABC9B308B87630050A7AC /* AppIcon.appiconset */; };
|
|
||||||
65AABCA5308B87E00050A7AC /* CardCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC9E308B87E00050A7AC /* CardCell.m */; };
|
65AABCA5308B87E00050A7AC /* CardCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABC9E308B87E00050A7AC /* CardCell.m */; };
|
||||||
65AABCA6308B87E00050A7AC /* ChipBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABCA1308B87E00050A7AC /* ChipBar.m */; };
|
65AABCA6308B87E00050A7AC /* ChipBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABCA1308B87E00050A7AC /* ChipBar.m */; };
|
||||||
65AABCA7308B87E00050A7AC /* BVGTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABCA3308B87E00050A7AC /* BVGTheme.m */; };
|
65AABCA7308B87E00050A7AC /* BVGTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = 65AABCA3308B87E00050A7AC /* BVGTheme.m */; };
|
||||||
@@ -78,7 +77,6 @@
|
|||||||
65AABC94308B83BE0050A7AC /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
65AABC94308B83BE0050A7AC /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
||||||
65AABC95308B83BE0050A7AC /* BVGSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BVGSettings.m; sourceTree = "<group>"; };
|
65AABC95308B83BE0050A7AC /* BVGSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BVGSettings.m; sourceTree = "<group>"; };
|
||||||
65AABC97308B83BE0050A7AC /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
65AABC97308B83BE0050A7AC /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
||||||
65AABC9B308B87630050A7AC /* AppIcon.appiconset */ = {isa = PBXFileReference; lastKnownFileType = folder; path = AppIcon.appiconset; sourceTree = "<group>"; };
|
|
||||||
65AABC9D308B87E00050A7AC /* CardCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardCell.h; sourceTree = "<group>"; };
|
65AABC9D308B87E00050A7AC /* CardCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardCell.h; sourceTree = "<group>"; };
|
||||||
65AABC9E308B87E00050A7AC /* CardCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CardCell.m; sourceTree = "<group>"; };
|
65AABC9E308B87E00050A7AC /* CardCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CardCell.m; sourceTree = "<group>"; };
|
||||||
65AABC9F308B87E00050A7AC /* ChipBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChipBar.h; sourceTree = "<group>"; };
|
65AABC9F308B87E00050A7AC /* ChipBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChipBar.h; sourceTree = "<group>"; };
|
||||||
@@ -137,7 +135,6 @@
|
|||||||
65AABC74308B7A0E0050A7AC /* BVGAPI.h */,
|
65AABC74308B7A0E0050A7AC /* BVGAPI.h */,
|
||||||
65AABC93308B83BE0050A7AC /* BVGSettings.h */,
|
65AABC93308B83BE0050A7AC /* BVGSettings.h */,
|
||||||
65AABC95308B83BE0050A7AC /* BVGSettings.m */,
|
65AABC95308B83BE0050A7AC /* BVGSettings.m */,
|
||||||
65AABC9B308B87630050A7AC /* AppIcon.appiconset */,
|
|
||||||
65AABC97308B83BE0050A7AC /* SettingsViewController.h */,
|
65AABC97308B83BE0050A7AC /* SettingsViewController.h */,
|
||||||
65AABC94308B83BE0050A7AC /* SettingsViewController.m */,
|
65AABC94308B83BE0050A7AC /* SettingsViewController.m */,
|
||||||
65AABC76308B7A0E0050A7AC /* BVGAPI.m */,
|
65AABC76308B7A0E0050A7AC /* BVGAPI.m */,
|
||||||
@@ -235,7 +232,6 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
65AABCAC308B91540050A7AC /* add_files.rb in Resources */,
|
65AABCAC308B91540050A7AC /* add_files.rb in Resources */,
|
||||||
65AABC9C308B87630050A7AC /* AppIcon.appiconset in Resources */,
|
|
||||||
659F88E3308B5CFA00D46649 /* LaunchScreen.storyboard in Resources */,
|
659F88E3308B5CFA00D46649 /* LaunchScreen.storyboard in Resources */,
|
||||||
659F88E0308B5CFA00D46649 /* Assets.xcassets in Resources */,
|
659F88E0308B5CFA00D46649 /* Assets.xcassets in Resources */,
|
||||||
65AABC8B308B7D8C0050A7AC /* LIESMICH.txt in Resources */,
|
65AABC8B308B7D8C0050A7AC /* LIESMICH.txt in Resources */,
|
||||||
|
|||||||
@@ -16,9 +16,38 @@
|
|||||||
@property (nonatomic, strong) UITabBarController *tabs;
|
@property (nonatomic, strong) UITabBarController *tabs;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
// Absturz-Melder: speichert Grund + Stack einer nicht abgefangenen Exception,
|
||||||
|
// beim naechsten Start wird beides angezeigt (iOS 9 schreibt den Grund nicht in den Crash-Report).
|
||||||
|
static NSString * const kLastCrashKey = @"lastCrash";
|
||||||
|
|
||||||
|
static void BVGUncaughtException(NSException *e) {
|
||||||
|
NSArray *stack = e.callStackSymbols ?: @[];
|
||||||
|
stack = [stack subarrayWithRange:NSMakeRange(0, MIN((NSUInteger)25, stack.count))];
|
||||||
|
NSString *report = [NSString stringWithFormat:@"%@\n%@\n\n%@", e.name, e.reason ?: @"(kein Grund)",
|
||||||
|
[stack componentsJoinedByString:@"\n"]];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:report forKey:kLastCrashKey];
|
||||||
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
}
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
- (void)showLastCrashIfAny {
|
||||||
|
NSString *report = [[NSUserDefaults standardUserDefaults] stringForKey:kLastCrashKey];
|
||||||
|
if (!report) return;
|
||||||
|
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kLastCrashKey];
|
||||||
|
|
||||||
|
UIAlertController *a = [UIAlertController alertControllerWithTitle:@"Letzter Absturz"
|
||||||
|
message:report
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[a addAction:[UIAlertAction actionWithTitle:@"Kopieren" style:UIAlertActionStyleDefault handler:^(UIAlertAction *x) {
|
||||||
|
[UIPasteboard generalPasteboard].string = report;
|
||||||
|
}]];
|
||||||
|
[a addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
|
[self.window.rootViewController presentViewController:a animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
NSSetUncaughtExceptionHandler(&BVGUncaughtException);
|
||||||
[application registerUserNotificationSettings:
|
[application registerUserNotificationSettings:
|
||||||
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge)
|
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge)
|
||||||
categories:nil]];
|
categories:nil]];
|
||||||
@@ -48,6 +77,9 @@
|
|||||||
self.window.tintColor = [BVGTheme textPrimary];
|
self.window.tintColor = [BVGTheme textPrimary];
|
||||||
self.window.rootViewController = self.tabs;
|
self.window.rootViewController = self.tabs;
|
||||||
[self.window makeKeyAndVisible];
|
[self.window makeKeyAndVisible];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
[self showLastCrashIfAny];
|
||||||
|
});
|
||||||
|
|
||||||
// Favoriten in die iOS-Suche aufnehmen (falls frisch installiert)
|
// Favoriten in die iOS-Suche aufnehmen (falls frisch installiert)
|
||||||
for (NSDictionary *f in [BVGAPI favorites]) [BVGAPI indexStopInSpotlight:f[@"id"] name:f[@"name"]];
|
for (NSDictionary *f in [BVGAPI favorites]) [BVGAPI indexStopInSpotlight:f[@"id"] name:f[@"name"]];
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ extern NSString * const BVGAlarmsChangedNotification;
|
|||||||
|
|
||||||
// Netzwerk
|
// Netzwerk
|
||||||
+ (void)getJSON:(NSString *)path completion:(void (^)(id json, NSError *error))completion;
|
+ (void)getJSON:(NSString *)path completion:(void (^)(id json, NSError *error))completion;
|
||||||
+ (NSString *)encode:(NSString *)s;
|
+ (NSString *)encode:(id)value; // NSString, NSNumber, nil/NSNull -> URL-kodiert
|
||||||
+ (NSString *)lastSource; // "serverlele" oder "transport.rest" - wer zuletzt geantwortet hat
|
+ (NSString *)lastSource; // "serverlele" oder "transport.rest" - wer zuletzt geantwortet hat
|
||||||
|
|
||||||
// Zeit
|
// Zeit
|
||||||
|
|||||||
@@ -87,6 +87,22 @@ NSString * const BVGAlarmsChangedNotification = @"BVGAlarmsChanged";
|
|||||||
}] resume];
|
}] resume];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fuer URL-Pfade und -Parameter: nur ASCII-Buchstaben/Ziffern bleiben unkodiert
|
||||||
|
// (sonst liefert NSURL bei Umlauten nil). Nimmt auch NSNumber/NSNull entgegen.
|
||||||
|
+ (NSString *)encode:(id)value {
|
||||||
|
NSString *s = nil;
|
||||||
|
if ([value isKindOfClass:[NSString class]]) s = value;
|
||||||
|
else if (value && value != [NSNull null]) s = [value description];
|
||||||
|
if (!s.length) return @"";
|
||||||
|
static NSCharacterSet *allowed;
|
||||||
|
static dispatch_once_t once;
|
||||||
|
dispatch_once(&once, ^{
|
||||||
|
allowed = [NSCharacterSet characterSetWithCharactersInString:
|
||||||
|
@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"];
|
||||||
|
});
|
||||||
|
return [s stringByAddingPercentEncodingWithAllowedCharacters:allowed] ?: @"";
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Zeit
|
#pragma mark - Zeit
|
||||||
|
|
||||||
+ (NSDateFormatter *)isoFormatter {
|
+ (NSDateFormatter *)isoFormatter {
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Prueft, ob jede in einer .h deklarierte Methode in der passenden .m implementiert ist.
|
||||||
|
Hintergrund: Objective-C kompiliert auch dann, wenn eine Methode fehlt - die App stuerzt erst
|
||||||
|
zur Laufzeit mit "unrecognized selector" ab.
|
||||||
|
|
||||||
|
Aufruf (im Projektordner): python3 BVGNearby/check_methods.py BVGNearby
|
||||||
|
Rueckgabe: 0 = alles da, 1 = etwas fehlt (bricht z.B. deploy.sh ab)
|
||||||
|
"""
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
folder = sys.argv[1] if len(sys.argv) > 1 else "."
|
||||||
|
missing = []
|
||||||
|
|
||||||
|
for header in sorted(glob.glob(os.path.join(folder, "*.h"))):
|
||||||
|
impl_path = header[:-2] + ".m"
|
||||||
|
if not os.path.exists(impl_path):
|
||||||
|
continue
|
||||||
|
hdr = open(header, encoding="utf-8").read()
|
||||||
|
impl = open(impl_path, encoding="utf-8").read()
|
||||||
|
for decl in re.findall(r"^[+-]\s*\([^)]*\)\s*[^;]+;", hdr, re.M):
|
||||||
|
kind = decl[0]
|
||||||
|
parts = re.findall(r"(\w+)\s*:", decl)
|
||||||
|
if parts:
|
||||||
|
selector = "".join(p + ":" for p in parts)
|
||||||
|
pattern = (r"^" + re.escape(kind) + r"\s*\([^)]*\)\s*"
|
||||||
|
+ r".*?".join(re.escape(p) + r"\s*:" for p in parts) + r"[^;{]*\{")
|
||||||
|
else:
|
||||||
|
selector = re.match(r"^[+-]\s*\([^)]*\)\s*(\w+)", decl).group(1)
|
||||||
|
pattern = r"^" + re.escape(kind) + r"\s*\([^)]*\)\s*" + re.escape(selector) + r"\s*\{"
|
||||||
|
if not re.search(pattern, impl, re.M | re.S):
|
||||||
|
missing.append(f"{os.path.basename(impl_path)}: {kind}{selector}")
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
print("FEHLENDE METHODEN (App würde abstürzen):")
|
||||||
|
print("\n".join(" " + m for m in missing))
|
||||||
|
sys.exit(1)
|
||||||
|
print("Methoden-Check: alle deklarierten Methoden sind implementiert.")
|
||||||
Reference in new issue
Block a user