2
0

Add support for Answers and improved Fabric integration.

This commit is contained in:
Maarten Billemont 2017-04-29 23:03:50 -04:00
parent 07e55140ac
commit 6d9be3fdfe
26 changed files with 237 additions and 129 deletions

View File

@ -42,7 +42,6 @@
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; };
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D39943D01E70DAC3B0DF76 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D396C311C3725870343EE0 /* mpw-util.c */; };
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D395105935859D71679931 /* MPOverlayViewController.m */; };
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */; };
@ -87,6 +86,9 @@
DA0CC5361EAB99BA009A8ED9 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5241EAB99BA009A8ED9 /* IASKTextField.m */; };
DA0CC5371EAB99BA009A8ED9 /* IASKTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */; };
DA0CC5381EAB99BA009A8ED9 /* IASKTextViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */; };
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */; };
DA0CC5411EB57BD4009A8ED9 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */; };
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA141191922FED80032B392 /* Crashlytics.framework */; };
DA24EBAE19DAD08900FF010B /* tip_basic_black_top.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38941711E29700CF925C /* tip_basic_black_top.png */; };
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38951711E29700CF925C /* tip_basic_black_top@2x.png */; };
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE619DAD6DE00FF010B /* Icon-320.png */; };
@ -114,7 +116,6 @@
DA29993219C9132F00AF7DF1 /* thumb_generated_login@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA29993119C9132F00AF7DF1 /* thumb_generated_login@3x.png */; };
DA29993319C9214600AF7DF1 /* icon_star-hollow.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD382A1711E29600CF925C /* icon_star-hollow.png */; };
DA29993419C9214600AF7DF1 /* icon_star-hollow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD382B1711E29600CF925C /* icon_star-hollow@2x.png */; };
DA2C3D611BD95EEE001137B3 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D601BD95EEE001137B3 /* Fabric.framework */; };
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D621BD96126001137B3 /* libc++.tbd */; };
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; };
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; };
@ -165,7 +166,6 @@
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
DA48856019A5A82E000C2D79 /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA141191922FED80032B392 /* Crashlytics.framework */; };
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
@ -335,7 +335,6 @@
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379A1711E29600CF925C /* icon_key.png */; };
DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379B1711E29600CF925C /* icon_key@2x.png */; };
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA269A1705DF81002C6C22 /* Crashlytics.plist */; };
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
@ -667,6 +666,8 @@
DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextView.m; sourceTree = "<group>"; };
DA0CC5271EAB99BA009A8ED9 /* IASKTextViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextViewCell.h; sourceTree = "<group>"; };
DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextViewCell.m; sourceTree = "<group>"; };
DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Fabric.plist; sourceTree = "<group>"; };
DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
DA24EBB219DAD4D000FF010B /* Icon-60.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60.png"; sourceTree = "<group>"; };
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@2x.png"; sourceTree = "<group>"; };
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@3x.png"; sourceTree = "<group>"; };
@ -1496,7 +1497,6 @@
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../Source/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
DACA269A1705DF81002C6C22 /* Crashlytics.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Crashlytics.plist; sourceTree = "<group>"; };
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
@ -1623,6 +1623,7 @@
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */,
DAE2725A19C93B8E007C5262 /* StoreKit.framework in Frameworks */,
@ -1634,15 +1635,13 @@
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */,
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */,
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */,
DA48856019A5A82E000C2D79 /* Crashlytics.framework in Frameworks */,
DAC632891486D9690075AEA5 /* Security.framework in Frameworks */,
DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */,
DA0979171E9A81EE00F0BFE8 /* libsodium.a in Frameworks */,
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */,
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */,
DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */,
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */,
DA2C3D611BD95EEE001137B3 /* Fabric.framework in Frameworks */,
DA0CC5411EB57BD4009A8ED9 /* Fabric.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1861,6 +1860,14 @@
path = Views;
sourceTree = "<group>";
};
DA0CC5391EB57B5C009A8ED9 /* Fabric */ = {
isa = PBXGroup;
children = (
DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */,
);
path = Fabric;
sourceTree = "<group>";
};
DA24EBB019DAD4D000FF010B /* ios */ = {
isa = PBXGroup;
children = (
@ -2022,6 +2029,7 @@
DAA141181922FED80032B392 /* iOS */ = {
isa = PBXGroup;
children = (
DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */,
DAA141191922FED80032B392 /* Crashlytics.framework */,
);
path = iOS;
@ -2908,7 +2916,7 @@
DACA23B41705DF7D002C6C22 /* Resources */ = {
isa = PBXGroup;
children = (
DACA26991705DF81002C6C22 /* Crashlytics */,
DA0CC5391EB57B5C009A8ED9 /* Fabric */,
DACA29701705E1A8002C6C22 /* Data */,
DAE1EF2417E942DE00BC0086 /* Localizable.strings */,
DABD360D1711E29400CF925C /* Media */,
@ -2916,14 +2924,6 @@
path = Resources;
sourceTree = "<group>";
};
DACA26991705DF81002C6C22 /* Crashlytics */ = {
isa = PBXGroup;
children = (
DACA269A1705DF81002C6C22 /* Crashlytics.plist */,
);
path = Crashlytics;
sourceTree = "<group>";
};
DACA29701705E1A8002C6C22 /* Data */ = {
isa = PBXGroup;
children = (
@ -3287,7 +3287,7 @@
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */,
DAD3125D155288AA00A3F9ED /* Run Script: Fabric */,
);
buildRules = (
);
@ -3548,7 +3548,7 @@
buildActionMask = 2147483647;
files = (
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */,
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
@ -3778,19 +3778,19 @@
shellScript = "exec Scripts/genassets";
showEnvVarsInLog = 0;
};
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = {
DAD3125D155288AA00A3F9ED /* Run Script: Fabric */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script: Crashlytics";
name = "Run Script: Fabric";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -e";
shellScript = "[[ $DEPLOYMENT_LOCATION != YES ]] && exit\n\napiKey=$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" Resources/Crashlytics/Crashlytics.plist)\n[[ $apiKey ]] && External/iOS/Crashlytics.framework/run \"$apiKey\"";
shellScript = "[[ $DEPLOYMENT_LOCATION != YES ]] && exit\n\napiKey=$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" Resources/Fabric/Fabric.plist)\n[[ $apiKey ]] && External/iOS/Fabric.framework/run \"$apiKey\"";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -4147,7 +4147,6 @@
);
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
@ -4263,6 +4262,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
"CRASHLYTICS=1",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@ -4412,7 +4412,6 @@
);
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
@ -4440,7 +4439,6 @@
);
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",

View File

@ -27,6 +27,7 @@
DA09745B1E99582900F0BFE8 /* mpw-tests.c in Sources */ = {isa = PBXBuildFile; fileRef = DA0974571E99582200F0BFE8 /* mpw-tests.c */; };
DA09745E1E99586600F0BFE8 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA09745D1E99586600F0BFE8 /* libxml2.tbd */; };
DA0979681E9A834C00F0BFE8 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
DA0CC53E1EB57B69009A8ED9 /* Fabric.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0CC53D1EB57B69009A8ED9 /* Fabric.plist */; };
DA1000801998A4C6002B873F /* openssl in Headers */ = {isa = PBXBuildFile; fileRef = DAE8E65719867AF500416A0F /* openssl */; settings = {ATTRIBUTES = (Public, ); }; };
DA16B341170661DB000A0EAB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B340170661DB000A0EAB /* Carbon.framework */; };
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
@ -148,7 +149,6 @@
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24581705DF7D002C6C22 /* menu-icon.png */; };
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA269A1705DF81002C6C22 /* Crashlytics.plist */; };
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
@ -350,6 +350,7 @@
DA0979531E9A824700F0BFE8 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
DA0979541E9A824700F0BFE8 /* sodium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sodium.h; sourceTree = "<group>"; };
DA0979571E9A824700F0BFE8 /* libsodium.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsodium.a; sourceTree = "<group>"; };
DA0CC53D1EB57B69009A8ED9 /* Fabric.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Fabric.plist; sourceTree = "<group>"; };
DA16B340170661DB000A0EAB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
DA16B343170661EE000A0EAB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPPasswordWindowController.xib; sourceTree = "<group>"; };
@ -911,7 +912,6 @@
DACA24581705DF7D002C6C22 /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
DACA269A1705DF81002C6C22 /* Crashlytics.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Crashlytics.plist; sourceTree = "<group>"; };
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
@ -1132,6 +1132,14 @@
path = lib;
sourceTree = "<group>";
};
DA0CC53C1EB57B69009A8ED9 /* Fabric */ = {
isa = PBXGroup;
children = (
DA0CC53D1EB57B69009A8ED9 /* Fabric.plist */,
);
path = Fabric;
sourceTree = "<group>";
};
DA2508F819513C1400AC23F1 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
@ -1772,8 +1780,8 @@
DACA23B41705DF7D002C6C22 /* Resources */ = {
isa = PBXGroup;
children = (
DA0CC53C1EB57B69009A8ED9 /* Fabric */,
DA09745F1E995EB500F0BFE8 /* mpw_tests.xml */,
DACA26991705DF81002C6C22 /* Crashlytics */,
DACA29701705E1A8002C6C22 /* Data */,
DACA23B51705DF7D002C6C22 /* Media */,
);
@ -1856,14 +1864,6 @@
path = Fonts;
sourceTree = "<group>";
};
DACA26991705DF81002C6C22 /* Crashlytics */ = {
isa = PBXGroup;
children = (
DACA269A1705DF81002C6C22 /* Crashlytics.plist */,
);
path = Crashlytics;
sourceTree = "<group>";
};
DACA29701705E1A8002C6C22 /* Data */ = {
isa = PBXGroup;
children = (
@ -2086,7 +2086,7 @@
DA5BFA42147E415C00F98B1E /* Resources */,
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */,
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */,
DAD3125D155288AA00A3F9ED /* Run Script: Fabric */,
);
buildRules = (
);
@ -2295,13 +2295,13 @@
DACA27331705DF81002C6C22 /* avatar-12@2x.png in Resources */,
DACA27341705DF81002C6C22 /* avatar-2@2x.png in Resources */,
DA60717D195D040500CA98B5 /* icon_gear@2x.png in Resources */,
DA0CC53E1EB57B69009A8ED9 /* Fabric.plist in Resources */,
DACA27351705DF81002C6C22 /* avatar-11.png in Resources */,
DACA27361705DF81002C6C22 /* avatar-0@2x.png in Resources */,
DACA27371705DF81002C6C22 /* avatar-10@2x.png in Resources */,
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */,
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
@ -2359,19 +2359,19 @@
shellPath = "/bin/sh -e";
shellScript = "exec Scripts/updatePlist";
};
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = {
DAD3125D155288AA00A3F9ED /* Run Script: Fabric */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script: Crashlytics";
name = "Run Script: Fabric";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/sh -e";
shellScript = "[[ $DEPLOYMENT_LOCATION != YES ]] && exit\n\napiKey=$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" Resources/Crashlytics/Crashlytics.plist)\n[[ $apiKey ]] && External/Mac/Fabric.framework/run \"$apiKey\" 410fb41450e3a2e50fa8357682d812ecd3e1846f2141a99bdb9d3a6a981ad69c";
shellScript = "[[ $DEPLOYMENT_LOCATION != YES ]] && exit\n\napiKey=$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" Resources/Fabric/Fabric.plist)\n[[ $apiKey ]] && External/Mac/Fabric.framework/run \"$apiKey\" 410fb41450e3a2e50fa8357682d812ecd3e1846f2141a99bdb9d3a6a981ad69c";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

View File

@ -55,14 +55,14 @@ setSettingWithTitle "Copyright" "$(getPlistWithKey NSHumanReadableCopyright)"
if [[ $DEPLOYMENT_LOCATION = YES ]]; then
# This build is a release. Do some release checks.
crashlyticsPlist="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/Crashlytics.plist"
fabricPlist="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/Fabric.plist"
passed=1
[[ $description != *-dirty ]] || \
{ passed=0; err 'ERROR: Cannot release a dirty version, first commit any changes.'; }
[[ $build == 0 ]] || \
{ passed=0; err 'ERROR: Commit is not tagged for release, first tag accordingly.'; }
[[ -r "$crashlyticsPlist" && $(PlistBuddy -c "Print :'API Key'" "$crashlyticsPlist" 2>/dev/null) ]] || \
{ passed=0; err 'ERROR: Cannot release: Crashlytics API key is missing.'; }
[[ -r "$fabricPlist" && $(PlistBuddy -c "Print :'API Key'" "$fabricPlist" 2>/dev/null) ]] || \
{ passed=0; err 'ERROR: Cannot release: Fabric API key is missing.'; }
(( passed )) || \
{ ftl "Failed to pass release checks. Fix the above errors and re-try. Aborting."; exit 1; }
fi

View File

@ -93,7 +93,7 @@ NSOperationQueue *_mpwQueue = nil;
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", self.version, user];
NSArray *migrationSites = [moc executeFetchRequest:migrationRequest error:&error];
if (!migrationSites) {
err( @"While looking for sites to migrate: %@", [error fullDescription] );
MPError( error, @"While looking for sites to migrate." );
return NO;
}

View File

@ -29,7 +29,7 @@
@protocol MPInAppDelegate
- (void)updateWithProducts:(NSArray /* SKProduct */ *)products;
- (void)updateWithProducts:(NSDictionary<NSString *, SKProduct *> *)products;
- (void)updateWithTransaction:(SKPaymentTransaction *)transaction;
@end

View File

@ -23,7 +23,8 @@
@implementation MPAppDelegate_Shared(InApp)
PearlAssociatedObjectProperty( NSArray*, Products, products );
PearlAssociatedObjectProperty( NSDictionary*, Products, products );
PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObservers );
- (void)registerProductsObserver:(id<MPInAppDelegate>)delegate {
@ -101,11 +102,25 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
}
#endif
for (SKProduct *product in self.products)
for (SKProduct *product in [self.products allValues])
if ([product.productIdentifier isEqualToString:productIdentifier]) {
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
if (payment) {
payment.quantity = quantity;
[[self paymentQueue] addPayment:payment];
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
[Answers logAddToCartWithPrice:product.price currency:product.priceLocale.currencyCode itemName:product.localizedTitle
itemType:@"InApp" itemId:product.productIdentifier
customAttributes:nil];
[Answers logStartCheckoutWithPrice:product.price currency:product.priceLocale.currencyCode itemCount:@(quantity)
customAttributes:@{
@"products": @[ productIdentifier ],
}];
#endif
}
}
return;
}
}
@ -114,8 +129,13 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
inf( @"products: %@, invalid: %@", response.products, response.invalidProductIdentifiers );
self.products = response.products;
if ([response.invalidProductIdentifiers count])
inf( @"Invalid products: %@", response.invalidProductIdentifiers );
NSMutableDictionary *products = [NSMutableDictionary dictionaryWithCapacity:[response.products count]];
for (SKProduct *product in response.products)
products[product.productIdentifier] = product;
self.products = products;
for (id<MPInAppDelegate> productObserver in self.productObservers)
[productObserver updateWithProducts:self.products];
@ -123,6 +143,8 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
MPError( error, @"StoreKit request (%@) failed.", request );
#if TARGET_OS_IPHONE
[PearlAlert showAlertWithTitle:@"Purchase Failed" message:
strf( @"%@\n\n%@", error.localizedDescription,
@ -131,7 +153,6 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
cancelTitle:@"OK" otherTitles:nil];
#else
#endif
err( @"StoreKit request (%@) failed: %@", request, [error fullDescription] );
}
- (void)requestDidFinish:(SKRequest *)request {
@ -147,21 +168,37 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
dbg( @"transaction updated: %@ -> %d", transaction.payment.productIdentifier, (int)(transaction.transactionState) );
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased: {
inf( @"purchased: %@", transaction.payment.productIdentifier );
inf( @"Purchased: %@", transaction.payment.productIdentifier );
NSMutableDictionary *attributes = [NSMutableDictionary new];
if ([transaction.payment.productIdentifier isEqualToString:MPProductFuel]) {
float currentFuel = [[MPiOSConfig get].developmentFuelRemaining floatValue];
float purchasedFuel = transaction.payment.quantity / MP_FUEL_HOURLY_RATE;
[MPiOSConfig get].developmentFuelRemaining = @(currentFuel + purchasedFuel);
if (![MPiOSConfig get].developmentFuelChecked || currentFuel < DBL_EPSILON)
[MPiOSConfig get].developmentFuelChecked = [NSDate date];
[attributes addEntriesFromDictionary:@{
@"currentFuel" : @(currentFuel),
@"purchasedFuel": @(purchasedFuel),
}];
}
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
forKey:transaction.payment.productIdentifier];
[queue finishTransaction:transaction];
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
SKProduct *product = self.products[transaction.payment.productIdentifier];
[Answers logPurchaseWithPrice:product.price currency:product.priceLocale.currencyCode success:@YES
itemName:product.localizedTitle itemType:@"InApp" itemId:product.productIdentifier
customAttributes:attributes];
#endif
}
break;
}
case SKPaymentTransactionStateRestored: {
inf( @"restored: %@", transaction.payment.productIdentifier );
inf( @"Restored: %@", transaction.payment.productIdentifier );
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
forKey:transaction.payment.productIdentifier];
[queue finishTransaction:transaction];
@ -173,6 +210,18 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
case SKPaymentTransactionStateFailed:
err( @"Transaction failed: %@, reason: %@", transaction.payment.productIdentifier, [transaction.error fullDescription] );
[queue finishTransaction:transaction];
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
SKProduct *product = self.products[transaction.payment.productIdentifier];
[Answers logPurchaseWithPrice:product.price currency:product.priceLocale.currencyCode success:@YES
itemName:product.localizedTitle itemType:@"InApp" itemId:product.productIdentifier
customAttributes:@{
@"state" : @"Failed",
@"reason": [transaction.error fullDescription],
}];
#endif
}
break;
}
@ -185,7 +234,7 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
err( @"StoreKit restore failed: %@", [error fullDescription] );
MPError( error, @"StoreKit restore failed." );
}
@end

View File

@ -16,12 +16,13 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#import <Crashlytics/Answers.h>
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
@interface MPAppDelegate_Shared()
@property(strong, nonatomic) MPKey *key;
@property(strong, atomic) MPKey *key;
@end
@ -177,6 +178,14 @@ static NSDictionary *createKeyQuery(MPUserEntity *user, BOOL newItem, MPKeyOrigi
else
dbg( @"Automatic login failed for user: %@", user.userID );
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
[Answers logLoginWithMethod:password? @"Password": @"Automatic" success:@NO customAttributes:@{
@"algorithm": @(user.algorithm.version),
}];
#endif
}
return NO;
}
inf( @"Logged in user: %@", user.userID );
@ -198,8 +207,11 @@ static NSDictionary *createKeyQuery(MPUserEntity *user, BOOL newItem, MPKeyOrigi
@try {
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
[[Crashlytics sharedInstance] setObjectValue:user.userID forKey:@"username"];
[[Crashlytics sharedInstance] setUserName:user.userID];
[Answers logLoginWithMethod:password? @"Password": @"Automatic" success:@YES customAttributes:@{
@"algorithm": @(user.algorithm.version),
}];
#endif
}
}

View File

@ -26,9 +26,9 @@
#endif
@property(strong, nonatomic, readonly) MPKey *key;
@property(strong, nonatomic, readonly) NSManagedObjectID *activeUserOID;
@property(strong, nonatomic, readonly) NSPersistentStoreCoordinator *storeCoordinator;
@property(strong, atomic, readonly) MPKey *key;
@property(strong, atomic, readonly) NSManagedObjectID *activeUserOID;
@property(strong, atomic, readonly) NSPersistentStoreCoordinator *storeCoordinator;
+ (instancetype)get;

View File

@ -23,9 +23,9 @@
@interface MPAppDelegate_Shared()
@property(strong, nonatomic) MPKey *key;
@property(strong, nonatomic) NSManagedObjectID *activeUserOID;
@property(strong, nonatomic) NSPersistentStoreCoordinator *storeCoordinator;
@property(strong, atomic) MPKey *key;
@property(strong, atomic) NSManagedObjectID *activeUserOID;
@property(strong, atomic) NSPersistentStoreCoordinator *storeCoordinator;
@end
@ -76,12 +76,13 @@
NSError *error;
if (activeUser.objectID.isTemporaryID && ![activeUser.managedObjectContext obtainPermanentIDsForObjects:@[ activeUser ] error:&error])
err( @"Failed to obtain a permanent object ID after setting active user: %@", [error fullDescription] );
MPError( error, @"Failed to obtain a permanent object ID after setting active user." );
self.activeUserOID = activeUser.objectID;
}
- (void)handleCoordinatorError:(NSError *)error {
}
@end

View File

@ -237,7 +237,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSURL *localStoreURL = [self localStoreURL];
if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent]
withIntermediateDirectories:YES attributes:nil error:&error]) {
err( @"Couldn't create our application support directory: %@", [error fullDescription] );
MPError( error, @"Couldn't create our application support directory." );
return;
}
if (![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self localStoreURL]
@ -246,7 +246,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSInferMappingModelAutomaticallyOption : @YES,
STORE_OPTIONS
} error:&error]) {
err( @"Failed to open store: %@", [error fullDescription] );
MPError( error, @"Failed to open store." );
self.storeCorrupted = @YES;
[self handleCoordinatorError:error];
return;
@ -255,12 +255,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
#if TARGET_OS_IPHONE
PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, UIApp, [NSOperationQueue mainQueue],
#else
PearlAddNotificationObserver( NSApplicationWillResignActiveNotification, NSApp, [NSOperationQueue mainQueue],
#endif
^(MPAppDelegate_Shared *self, NSNotification *note) {
[self.mainManagedObjectContext saveToStore];
} );
#else
PearlAddNotificationObserver( NSApplicationWillResignActiveNotification, NSApp, [NSOperationQueue mainQueue],
^(MPAppDelegate_Shared *self, NSNotification *note) {
[self.mainManagedObjectContext saveToStore];
} );
#endif
// Perform a data sanity check on the newly loaded store to find and fix any issues.
if ([[MPConfig get].checkInconsistency boolValue])
@ -286,10 +289,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSError *error = nil;
for (NSPersistentStore *store in self.storeCoordinator.persistentStores) {
if (![self.storeCoordinator removePersistentStore:store error:&error])
err( @"Couldn't remove persistence store from coordinator: %@", [error fullDescription] );
MPError( error, @"Couldn't remove persistence store from coordinator." );
}
if (![[NSFileManager defaultManager] removeItemAtURL:self.localStoreURL error:&error])
err( @"Couldn't remove persistence store at URL %@: %@", self.localStoreURL, [error fullDescription] );
MPError( error, @"Couldn't remove persistence store at URL %@.", self.localStoreURL );
[self loadStore];
}
@ -307,7 +310,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
fetchRequest.entity = entity;
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
if (!objects) {
err( @"Failed to fetch %@ objects: %@", entity, [error fullDescription] );
MPError( error, @"Failed to fetch %@ objects.", entity );
continue;
}
@ -332,7 +335,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
- (void)migrateStore {
MPStoreMigrationLevel migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelLocalStoreKey];
MPStoreMigrationLevel migrationLevel = (MPStoreMigrationLevel)
[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelLocalStoreKey];
if (migrationLevel >= MPStoreMigrationLevelCurrent)
// Local store up-to-date.
return;
@ -375,7 +379,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
if (![NSPersistentStore migrateStore:oldLocalStoreURL withOptions:@{ STORE_OPTIONS }
toStore:newLocalStoreURL withOptions:@{ STORE_OPTIONS }
model:nil error:&error]) {
err( @"Couldn't migrate the old store to the new location: %@", [error fullDescription] );
MPError( error, @"Couldn't migrate the old store to the new location." );
return NO;
}
@ -422,7 +426,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSInferMappingModelAutomaticallyOption : @YES,
STORE_OPTIONS
} model:nil error:&error]) {
err( @"Couldn't migrate the old store to the new location: %@", [error fullDescription] );
MPError( error, @"Couldn't migrate the old store to the new location." );
return NO;
}
@ -459,7 +463,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSError *error = nil;
if (site.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ site ] error:&error])
err( @"Failed to obtain a permanent object ID after creating new site: %@", [error fullDescription] );
MPError( error, @"Failed to obtain a permanent object ID after creating new site." );
[context saveToStore];
@ -491,7 +495,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSError *error = nil;
if (![context obtainPermanentIDsForObjects:@[ newSite ] error:&error])
err( @"Failed to obtain a permanent object ID after changing object type: %@", [error fullDescription] );
MPError( error, @"Failed to obtain a permanent object ID after changing object type." );
[context deleteObject:site];
[context saveToStore];
@ -537,7 +541,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
initWithPattern:@"^#[[:space:]]*([^:]+): (.*)"
options:(NSRegularExpressionOptions)0 error:&error];
if (error) {
err( @"Error loading the header pattern: %@", [error fullDescription] );
MPError( error, @"Error loading the header pattern." );
return MPImportResultInternalError;
}
}
@ -551,7 +555,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
options:(NSRegularExpressionOptions)0 error:&error]
];
if (error) {
err( @"Error loading the site patterns: %@", [error fullDescription] );
MPError( error, @"Error loading the site patterns." );
return MPImportResultInternalError;
}
}
@ -610,7 +614,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", importUserName];
NSArray *users = [context executeFetchRequest:userFetchRequest error:&error];
if (!users) {
err( @"While looking for user: %@, error: %@", importUserName, [error fullDescription] );
MPError( error, @"While looking for user: %@.", importUserName );
return MPImportResultInternalError;
}
if ([users count] > 1) {
@ -694,7 +698,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
siteFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", siteName, user];
NSArray *existingSites = [context executeFetchRequest:siteFetchRequest error:&error];
if (!existingSites) {
err( @"Lookup of existing sites failed for site: %@, user: %@, error: %@", siteName, user.userID, [error fullDescription] );
MPError( error, @"Lookup of existing sites failed for site: %@, user: %@.", siteName, user.userID );
return MPImportResultInternalError;
}
if ([existingSites count]) {

View File

@ -20,7 +20,7 @@
[self.defaults registerDefaults:@{
NSStringFromSelector( @selector( askForReviews ) ) : @YES,
NSStringFromSelector( @selector( sendInfo ) ) : @NO,
NSStringFromSelector( @selector( sendInfo ) ) : @YES,
NSStringFromSelector( @selector( rememberLogin ) ) : @NO,
NSStringFromSelector( @selector( hidePasswords ) ) : @NO,
NSStringFromSelector( @selector( checkInconsistency ) ): @NO,

View File

@ -21,11 +21,11 @@
@try {
NSError *error = nil;
if (!(success = [self save:&error]))
err( @"While saving: %@", [error fullDescription] );
MPError( error, @"While saving." );
}
@catch (NSException *exception) {
success = NO;
err( @"While saving: %@", [exception fullDescription] );
err( @"While saving.\n%@", [exception fullDescription] );
}
}];

View File

@ -6,6 +6,9 @@
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Crashlytics/Crashlytics.h>
#import <Crashlytics/Answers.h>
__BEGIN_DECLS
extern NSString *const MPErrorDomain;
@ -19,4 +22,21 @@ extern NSString *const MPFoundInconsistenciesNotification;
extern NSString *const MPSitesImportedNotificationUserKey;
extern NSString *const MPInconsistenciesFixResultUserKey;
__END_DECLS
#ifdef CRASHLYTICS
#define MPError(error_, message, ...) ({ \
err( message @"%@%@", ##__VA_ARGS__, error_? @"\n": @"", [error_ fullDescription]?: @"" ); \
\
if ([[MPConfig get].sendInfo boolValue]) { \
[[Crashlytics sharedInstance] recordError:error_ withAdditionalUserInfo:@{ \
@"location": strf( @"%@:%d %@", @(basename((char *)__FILE__)), __LINE__, NSStringFromSelector(_cmd) ), \
}]; \
} \
})
#else
#define MPError(error_, ...) ({ \
err( message @"%@%@", ##__VA_ARGS__, error_? @"\n": @"", [error_ fullDescription]?: @"" ); \
})
#endif

View File

@ -78,7 +78,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[[Crashlytics sharedInstance] setUserIdentifier:[PearlKeyChain deviceIdentifier]];
[[Crashlytics sharedInstance] setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
[[Crashlytics sharedInstance] setUserName:@"Anonymous"];
[[Crashlytics sharedInstance] setObjectValue:@"Anonymous" forKey:@"username"];
[Crashlytics startWithAPIKey:crashlyticsAPIKey];
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
PearlLogLevel level = PearlLogLevelInfo;
@ -272,7 +271,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
if (error)
err( @"While reading imported sites from %@: %@", url, [error fullDescription] );
MPError( error, @"While reading imported sites from %@.", url );
if (!importedSitesData)
return;
@ -394,9 +393,9 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
inManagedObjectContext:moc];
newUser.name = name;
[moc saveToStore];
NSError *error = nil;
if (![moc obtainPermanentIDsForObjects:@[ newUser ] error:&error])
err( @"Failed to obtain permanent object ID for new user: %@", [error fullDescription] );
// NSError *error = nil;
// if (![moc obtainPermanentIDsForObjects:@[ newUser ] error:&error])
// MPError( error, @"Failed to obtain permanent object ID for new user." );
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self updateUsers];
@ -516,20 +515,23 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
NSError *coordinateError = nil;
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
[[[NSFileCoordinator alloc] initWithFilePresenter:nil] coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError
byAccessor:^(NSURL *newURL) {
[[[NSFileCoordinator alloc] initWithFilePresenter:nil] coordinateWritingItemAtURL:savePanel.URL options:0
error:&coordinateError byAccessor:
^(NSURL *newURL) {
NSError *writeError = nil;
if (![exportedSites writeToURL:newURL atomically:NO
encoding:NSUTF8StringEncoding
error:&writeError])
if (![exportedSites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
MPError( writeError, @"Could not write to the export file." );
PearlMainQueue( ^{
[[NSAlert alertWithError:writeError] runModal];
} );
}];
if (coordinateError)
if (coordinateError) {
MPError( coordinateError, @"Write access to the export file could not be obtained." );
PearlMainQueue( ^{
[[NSAlert alertWithError:coordinateError] runModal];
} );
}
}
- (void)updateUsers {
@ -567,7 +569,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ];
NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error];
if (!users)
err( @"Failed to load users: %@", [error fullDescription] );
MPError( error, @"Failed to load users." );
if (![users count]) {
NSMenuItem *noUsersItem = [self.usersItem.submenu addItemWithTitle:@"No users" action:NULL keyEquivalent:@""];

View File

@ -555,7 +555,7 @@
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
if (!siteResults) {
prof_finish( @"executeFetchRequest: %@ // %@", fetchRequest.predicate, [error fullDescription] );
err( @"While fetching sites for completion: %@", [error fullDescription] );
MPError( error, @"While fetching sites for completion." );
return;
}
prof_rewind( @"executeFetchRequest: %@", fetchRequest.predicate );

View File

@ -115,7 +115,7 @@
NSError *error;
MPSiteEntity *entity = (MPSiteEntity *)[moc existingObjectWithID:_entityOID error:&error];
if (!entity)
err( @"Couldn't retrieve active site: %@", [error fullDescription] );
MPError( error, @"Couldn't retrieve active site." );
return entity;
}

View File

@ -333,12 +333,12 @@
question.keyword = keyword;
if ([context saveToStore]) {
if ([question.objectID isTemporaryID]) {
NSError *error = nil;
[context obtainPermanentIDsForObjects:@[ question ] error:&error];
if (error)
err( @"Failed to obtain permanent object ID: %@", [error fullDescription] );
}
// if ([question.objectID isTemporaryID]) {
// NSError *error = nil;
// [context obtainPermanentIDsForObjects:@[ question ] error:&error];
// if (error)
// MPError( error, @"Failed to obtain permanent object ID: %@" );
// }
_questionOID = question.objectID;
[self updateAnswerForQuestion:question ofSite:site];

View File

@ -395,7 +395,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
self.fetchedResultsController.fetchRequest.predicate =
[NSPredicate predicateWithFormat:@"name LIKE[cd] %@ AND user == %@", queryPattern, [MPiOSAppDelegate get].activeUserOID];
if (![self.fetchedResultsController performFetch:&error])
err( @"Couldn't fetch sites: %@", [error fullDescription] );
MPError( error, @"Couldn't fetch sites." );
PearlMainQueue( ^{
[self.passwordCollectionView updateDataSource:_passwordCollectionSections

View File

@ -39,6 +39,8 @@
@interface MPStoreProductCell : UITableViewCell
@property(nonatomic) IBOutlet UILabel *priceLabel;
@property(nonatomic) IBOutlet UILabel *titleLabel;
@property(nonatomic) IBOutlet UILabel *descriptionLabel;
@property(nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
@property(nonatomic) IBOutlet UIView *purchasedIndicator;

View File

@ -28,7 +28,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
@interface MPStoreViewController()<MPInAppDelegate>
@property(nonatomic, strong) NSNumberFormatter *currencyFormatter;
@property(nonatomic, strong) NSArray *products;
@property(nonatomic, strong) NSDictionary<NSString *, SKProduct *> *products;
@end
@ -43,7 +43,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
];
NSInteger storeVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"storeVersion"];
for (; storeVersion < [storeVersions count]; ++storeVersion)
[features appendFormat:@"%@\n", storeVersions[storeVersion]];
[features appendFormat:@"%@\n", storeVersions[(NSUInteger)storeVersion]];
if (![features length])
return nil;
@ -170,7 +170,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
#pragma mark - MPInAppDelegate
- (void)updateWithProducts:(NSArray *)products {
- (void)updateWithProducts:(NSDictionary<NSString *, SKProduct *> *)products {
self.products = products;
@ -218,7 +218,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
- (SKProduct *)productForCell:(MPStoreProductCell *)cell {
for (SKProduct *product in self.products)
for (SKProduct *product in [self.products allValues])
if ([self cellForProductIdentifier:product.productIdentifier] == cell)
return product;
@ -248,7 +248,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
[hideCells addObjectsFromArray:[self.allCellsBySection[0] array]];
[hideCells addObject:self.loadingCell];
for (SKProduct *product in self.products) {
for (SKProduct *product in [self.products allValues]) {
[self showCellForProductWithIdentifier:MPProductGenerateLogins ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductGenerateAnswers ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductOSIntegration ifProduct:product showingCells:showCells];
@ -313,6 +313,8 @@ PearlEnum( MPDevelopmentFuelConsumption,
BOOL purchased = [[MPiOSAppDelegate get] isFeatureUnlocked:productIdentifier];
NSInteger quantity = [self quantityForProductIdentifier:productIdentifier];
cell.priceLabel.text = purchased? @"": [self.currencyFormatter stringFromNumber:@([product.price floatValue] * quantity)];
cell.titleLabel.text = product.localizedTitle;
cell.descriptionLabel.text = product.localizedDescription;
cell.purchasedIndicator.visible = purchased;
}

View File

@ -16,6 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#import <Crashlytics/Answers.h>
#import "MPUsersViewController.h"
#import "MPEntities.h"
#import "MPAvatarCell.h"
@ -224,6 +225,17 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
user.defaultType = user.algorithm.defaultType;
user.avatar = newUserAvatar;
user.name = newUserName;
if ([[MPConfig get].sendInfo boolValue]) {
#ifdef CRASHLYTICS
[Answers logSignUpWithMethod:@"Manual"
success:@YES
customAttributes:@{
@"algorithm": @(user.algorithm.version),
@"avatar" : @(user.avatar),
}];
#endif
}
}
BOOL signedIn = [[MPiOSAppDelegate get] signInAsUser:user saveInContext:context
@ -719,7 +731,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
];
NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error];
if (!users) {
err( @"Failed to load users: %@", [error fullDescription] );
MPError( error, @"Failed to load users." );
self.userIDs = nil;
}

View File

@ -25,7 +25,6 @@
@property(nonatomic, strong) UIDocumentInteractionController *interactionController;
@property(nonatomic) UIBackgroundTaskIdentifier task;
@end
@implementation MPiOSAppDelegate
@ -59,10 +58,9 @@
[[Crashlytics sharedInstance] setUserIdentifier:[PearlKeyChain deviceIdentifier]];
[[Crashlytics sharedInstance] setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
[[Crashlytics sharedInstance] setUserName:@"Anonymous"];
[[Crashlytics sharedInstance] setObjectValue:@"Anonymous" forKey:@"username"];
[Crashlytics startWithAPIKey:crashlyticsAPIKey];
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
PearlLogLevel level = PearlLogLevelInfo;
PearlLogLevel level = PearlLogLevelWarn;
if ([[MPConfig get].sendInfo boolValue])
level = PearlLogLevelDebug;
@ -83,9 +81,6 @@
PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
[self updateConfigKey:note.object];
} );
// PearlAddNotificationObserver( kIASKAppSettingChanged, nil, nil, ^(id self, NSNotification *note) {
// [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object];
// } );
PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
} );
@ -155,7 +150,8 @@
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
if (error)
err( @"While reading imported sites from %@: %@", url, [error fullDescription] );
MPError( error, @"While reading imported sites from %@.", url );
if (!importedSitesData) {
[PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@",
[error localizedDescription]?: error )];
@ -483,7 +479,7 @@
NSError *error = nil;
if (![[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&error])
err( @"Failed to write export data to URL %@: %@", exportURL, [error fullDescription] );
MPError( error, @"Failed to write export data to URL %@.", exportURL );
else {
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
@ -574,7 +570,7 @@
static NSDictionary *crashlyticsInfo = nil;
if (crashlyticsInfo == nil)
crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]];
[[NSBundle mainBundle] URLForResource:@"Fabric" withExtension:@"plist"]];
return crashlyticsInfo;
}

View File

@ -60,7 +60,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>© 2011-2016 Lyndir</string>
<string>© 2011-2017</string>
<key>UIAppFonts</key>
<array>
<string>Exo2.0-Bold.otf</string>

View File

@ -6,7 +6,7 @@
<array>
<dict>
<key>FooterText</key>
<string>Enable this setting to send us carefully anonymized information to help us diagnose and resolve issues you might experience in the future.</string>
<string>Enable this setting to send carefully anonymized information to help us diagnose and resolve any issues you encounter in a future update.</string>
<key>Title</key>
<string></string>
<key>Type</key>
@ -50,7 +50,7 @@
<key>Key</key>
<string>sendInfo</string>
<key>DefaultValue</key>
<false/>
<true/>
</dict>
<dict>
<key>FooterText</key>

View File

@ -2620,8 +2620,10 @@ See </string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="cef-sc-aph" id="VmL-AX-R3f"/>
<outlet property="descriptionLabel" destination="Ra0-yS-99P" id="99B-ao-lE6"/>
<outlet property="priceLabel" destination="68f-wn-UlS" id="e99-ys-HtZ"/>
<outlet property="purchasedIndicator" destination="FWu-V6-mLT" id="Zqt-GG-e5v"/>
<outlet property="titleLabel" destination="Pax-1J-IZi" id="kVH-n6-mDs"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellGenerateAnswers" id="l1g-Ul-Vg8" userLabel="Generate Answers" customClass="MPStoreProductCell">
@ -2685,8 +2687,10 @@ See </string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="X2g-Go-2Hz" id="PvQ-bP-exW"/>
<outlet property="descriptionLabel" destination="yRH-27-edZ" id="pfv-na-UM3"/>
<outlet property="priceLabel" destination="9ct-IM-QKR" id="UTQ-L7-vbu"/>
<outlet property="purchasedIndicator" destination="N9y-ue-L8d" id="Ppv-ay-M1J"/>
<outlet property="titleLabel" destination="Kkl-gT-YAO" id="cHy-iU-oHr"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellOSIntegration" id="9Na-CL-jBq" userLabel="iOS Integration" customClass="MPStoreProductCell">
@ -2750,8 +2754,10 @@ See </string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="yUe-TX-fli" id="DH6-pK-fse"/>
<outlet property="descriptionLabel" destination="riF-bB-x5g" id="3v9-6H-PAK"/>
<outlet property="priceLabel" destination="3jH-eX-9N2" id="agT-az-dVU"/>
<outlet property="purchasedIndicator" destination="ec8-P9-KPY" id="M39-bc-Ksp"/>
<outlet property="titleLabel" destination="Zch-DS-J3I" id="cY2-FQ-q69"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellTouchID" id="8en-6R-GvR" userLabel="TouchID" customClass="MPStoreProductCell">
@ -2815,8 +2821,10 @@ See </string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="Dv5-t7-lL1" id="AFu-Dd-TgU"/>
<outlet property="descriptionLabel" destination="Yxc-Lr-382" id="47I-83-lgP"/>
<outlet property="priceLabel" destination="ZGg-O6-rsg" id="dAn-xu-gut"/>
<outlet property="purchasedIndicator" destination="yZX-ns-8oV" id="7x0-eq-oSs"/>
<outlet property="titleLabel" destination="e1D-jp-GBs" id="jFw-dm-vp6"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellFuel" id="le3-Q5-MSO" userLabel="Fuel" customClass="MPStoreProductCell">
@ -2908,7 +2916,9 @@ invested: 3.7 work hours</string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="eS4-59-Xny" id="kGW-fn-VqH"/>
<outlet property="descriptionLabel" destination="fz2-AO-aGW" id="xkc-xV-Z6Y"/>
<outlet property="priceLabel" destination="EbU-DV-fKF" id="pg2-8o-7We"/>
<outlet property="titleLabel" destination="Jnv-uN-xeg" id="Kxi-RE-ipa"/>
</connections>
</tableViewCell>
</cells>