[CHORE] Memory leaks investigation (#1675)
This commit is contained in:
parent
82fd91d2f4
commit
6a40d4cefb
|
@ -60,6 +60,8 @@ const emojiCount = (str) => {
|
|||
return counter;
|
||||
};
|
||||
|
||||
const parser = new Parser();
|
||||
|
||||
class Markdown extends PureComponent {
|
||||
static propTypes = {
|
||||
msg: PropTypes.string,
|
||||
|
@ -81,13 +83,9 @@ class Markdown extends PureComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.parser = this.createParser();
|
||||
this.renderer = this.createRenderer(props.preview);
|
||||
}
|
||||
|
||||
createParser = () => new Parser();
|
||||
|
||||
createRenderer = (preview = false) => new Renderer({
|
||||
renderers: {
|
||||
text: this.renderText,
|
||||
|
@ -385,7 +383,7 @@ class Markdown extends PureComponent {
|
|||
|
||||
if (preview) {
|
||||
m = m.split('\n').reduce((lines, line) => `${ lines } ${ line }`, '');
|
||||
const ast = this.parser.parse(m);
|
||||
const ast = parser.parse(m);
|
||||
return this.renderer.render(ast);
|
||||
}
|
||||
|
||||
|
@ -393,7 +391,7 @@ class Markdown extends PureComponent {
|
|||
return <Text style={[styles.text, { color: themes[theme].bodyText }]} numberOfLines={numberOfLines}>{m}</Text>;
|
||||
}
|
||||
|
||||
const ast = this.parser.parse(m);
|
||||
const ast = parser.parse(m);
|
||||
this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
|
||||
|
||||
this.editedMessage(ast);
|
||||
|
|
11
app/index.js
11
app/index.js
|
@ -43,6 +43,9 @@ import Tablet, { initTabletNav } from './tablet';
|
|||
import sharedStyles from './views/Styles';
|
||||
import { SplitContext } from './split';
|
||||
|
||||
import RoomsListView from './views/RoomsListView';
|
||||
import RoomView from './views/RoomView';
|
||||
|
||||
if (isIOS) {
|
||||
const RNScreens = require('react-native-screens');
|
||||
RNScreens.useScreens();
|
||||
|
@ -111,9 +114,7 @@ const OutsideStackModal = createStackNavigator({
|
|||
});
|
||||
|
||||
const RoomRoutes = {
|
||||
RoomView: {
|
||||
getScreen: () => require('./views/RoomView').default
|
||||
},
|
||||
RoomView,
|
||||
ThreadMessagesView: {
|
||||
getScreen: () => require('./views/ThreadMessagesView').default
|
||||
},
|
||||
|
@ -127,9 +128,7 @@ const RoomRoutes = {
|
|||
|
||||
// Inside
|
||||
const ChatsStack = createStackNavigator({
|
||||
RoomsListView: {
|
||||
getScreen: () => require('./views/RoomsListView').default
|
||||
},
|
||||
RoomsListView,
|
||||
RoomActionsView: {
|
||||
getScreen: () => require('./views/RoomActionsView').default
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { InteractionManager } from 'react-native';
|
||||
|
||||
import database from '../../database';
|
||||
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
||||
|
@ -23,7 +24,7 @@ let subQueue = {};
|
|||
let subTimer = null;
|
||||
let roomQueue = {};
|
||||
let roomTimer = null;
|
||||
const WINDOW_TIME = 1000;
|
||||
const WINDOW_TIME = 500;
|
||||
|
||||
const createOrUpdateSubscription = async(subscription, room) => {
|
||||
try {
|
||||
|
@ -176,7 +177,9 @@ const debouncedUpdateSub = (subscription) => {
|
|||
subQueue = {};
|
||||
subTimer = null;
|
||||
Object.keys(subBatch).forEach((key) => {
|
||||
createOrUpdateSubscription(subBatch[key]);
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
createOrUpdateSubscription(subBatch[key]);
|
||||
});
|
||||
});
|
||||
}, WINDOW_TIME);
|
||||
}
|
||||
|
@ -190,7 +193,9 @@ const debouncedUpdateRoom = (room) => {
|
|||
roomQueue = {};
|
||||
roomTimer = null;
|
||||
Object.keys(roomBatch).forEach((key) => {
|
||||
createOrUpdateSubscription(null, roomBatch[key]);
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
createOrUpdateSubscription(null, roomBatch[key]);
|
||||
});
|
||||
});
|
||||
}, WINDOW_TIME);
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ class List extends React.Component {
|
|||
rid: PropTypes.string,
|
||||
t: PropTypes.string,
|
||||
tmid: PropTypes.string,
|
||||
animated: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
listRef: PropTypes.func
|
||||
listRef: PropTypes.func,
|
||||
navigation: PropTypes.object
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -40,9 +40,17 @@ class List extends React.Component {
|
|||
loading: true,
|
||||
end: false,
|
||||
messages: [],
|
||||
refreshing: false
|
||||
refreshing: false,
|
||||
animated: false
|
||||
};
|
||||
this.init();
|
||||
this.didFocusListener = props.navigation.addListener('didFocus', () => {
|
||||
if (this.mounted) {
|
||||
this.setState({ animated: true });
|
||||
} else {
|
||||
this.state.animated = true;
|
||||
}
|
||||
});
|
||||
console.timeEnd(`${ this.constructor.name } init`);
|
||||
}
|
||||
|
||||
|
@ -130,6 +138,9 @@ class List extends React.Component {
|
|||
if (this.onEndReached && this.onEndReached.stop) {
|
||||
this.onEndReached.stop();
|
||||
}
|
||||
if (this.didFocusListener && this.didFocusListener.remove) {
|
||||
this.didFocusListener.remove();
|
||||
}
|
||||
console.countReset(`${ this.constructor.name }.render calls`);
|
||||
}
|
||||
|
||||
|
@ -180,7 +191,10 @@ class List extends React.Component {
|
|||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
update = () => {
|
||||
animateNextTransition();
|
||||
const { animated } = this.state;
|
||||
if (animated) {
|
||||
animateNextTransition();
|
||||
}
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
|
|
|
@ -182,8 +182,6 @@ class RoomView extends React.Component {
|
|||
this.findAndObserveRoom(this.rid);
|
||||
}
|
||||
|
||||
this.beginAnimating = false;
|
||||
this.didFocusListener = props.navigation.addListener('didFocus', () => this.beginAnimating = true);
|
||||
this.messagebox = React.createRef();
|
||||
this.list = React.createRef();
|
||||
this.willBlurListener = props.navigation.addListener('willBlur', () => this.mounted = false);
|
||||
|
@ -289,9 +287,6 @@ class RoomView extends React.Component {
|
|||
}
|
||||
}
|
||||
this.unsubscribe();
|
||||
if (this.didFocusListener && this.didFocusListener.remove) {
|
||||
this.didFocusListener.remove();
|
||||
}
|
||||
if (this.didMountInteraction && this.didMountInteraction.cancel) {
|
||||
this.didMountInteraction.cancel();
|
||||
}
|
||||
|
@ -321,7 +316,6 @@ class RoomView extends React.Component {
|
|||
navigation.navigate('RoomActionsView', { rid: this.rid, t: this.t, room });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
init = async() => {
|
||||
try {
|
||||
this.setState({ loading: true });
|
||||
|
@ -893,7 +887,9 @@ class RoomView extends React.Component {
|
|||
const {
|
||||
room, reactionsModalVisible, selectedMessage, loading, reacting
|
||||
} = this.state;
|
||||
const { user, baseUrl, theme } = this.props;
|
||||
const {
|
||||
user, baseUrl, theme, navigation
|
||||
} = this.props;
|
||||
const { rid, t } = room;
|
||||
|
||||
return (
|
||||
|
@ -916,7 +912,7 @@ class RoomView extends React.Component {
|
|||
room={room}
|
||||
renderRow={this.renderItem}
|
||||
loading={loading}
|
||||
animated={this.beginAnimating}
|
||||
navigation={navigation}
|
||||
/>
|
||||
{this.renderFooter()}
|
||||
{this.renderActions()}
|
||||
|
|
|
@ -182,6 +182,7 @@ class RoomsListView extends React.Component {
|
|||
console.time(`${ this.constructor.name } mount`);
|
||||
|
||||
this.gotSubscriptions = false;
|
||||
this.animated = false;
|
||||
const { width } = Dimensions.get('window');
|
||||
this.state = {
|
||||
searching: false,
|
||||
|
@ -215,9 +216,11 @@ class RoomsListView extends React.Component {
|
|||
}
|
||||
});
|
||||
this.didFocusListener = navigation.addListener('didFocus', () => {
|
||||
this.animated = true;
|
||||
this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||
});
|
||||
this.willBlurListener = navigation.addListener('willBlur', () => {
|
||||
this.animated = false;
|
||||
closeServerDropdown();
|
||||
if (this.backHandler && this.backHandler.remove) {
|
||||
this.backHandler.remove();
|
||||
|
@ -338,12 +341,11 @@ class RoomsListView extends React.Component {
|
|||
console.countReset(`${ this.constructor.name }.render calls`);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
onDimensionsChange = ({ window: { width } }) => this.setState({ width });
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
internalSetState = (...args) => {
|
||||
const { navigation } = this.props;
|
||||
if (navigation.isFocused()) {
|
||||
if (this.animated) {
|
||||
animateNextTransition();
|
||||
}
|
||||
this.setState(...args);
|
||||
|
@ -532,7 +534,7 @@ class RoomsListView extends React.Component {
|
|||
prid: item.prid,
|
||||
room: item
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
_onPressItem = async(item = {}) => {
|
||||
if (!item.search) {
|
||||
|
|
149
ios/Podfile.lock
149
ios/Podfile.lock
|
@ -34,35 +34,41 @@ PODS:
|
|||
- React-Core (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5)
|
||||
- Firebase/Core (6.8.1):
|
||||
- Firebase/Core (6.16.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (= 6.1.1)
|
||||
- Firebase/CoreOnly (6.8.1):
|
||||
- FirebaseCore (= 6.2.3)
|
||||
- FirebaseAnalytics (6.1.1):
|
||||
- FirebaseCore (~> 6.2)
|
||||
- FirebaseInstanceID (~> 4.2)
|
||||
- GoogleAppMeasurement (= 6.1.1)
|
||||
- FirebaseAnalytics (= 6.2.2)
|
||||
- Firebase/CoreOnly (6.16.0):
|
||||
- FirebaseCore (= 6.6.1)
|
||||
- FirebaseAnalytics (6.2.2):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstanceID (~> 4.3)
|
||||
- GoogleAppMeasurement (= 6.2.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseCore (6.2.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.0)
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
||||
- GoogleUtilities/Environment (~> 6.2)
|
||||
- GoogleUtilities/Logger (~> 6.2)
|
||||
- FirebaseCoreDiagnostics (1.0.1):
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
||||
- GoogleDataTransportCCTSupport (~> 1.0)
|
||||
- GoogleUtilities/Environment (~> 6.2)
|
||||
- GoogleUtilities/Logger (~> 6.2)
|
||||
- FirebaseCoreDiagnosticsInterop (1.0.0)
|
||||
- FirebaseInstanceID (4.2.5):
|
||||
- FirebaseCore (~> 6.0)
|
||||
- GoogleUtilities/Environment (~> 6.0)
|
||||
- GoogleUtilities/UserDefaults (~> 6.0)
|
||||
- nanopb (= 0.3.9011)
|
||||
- FirebaseCore (6.6.1):
|
||||
- FirebaseCoreDiagnostics (~> 1.2)
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- FirebaseCoreDiagnostics (1.2.0):
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleDataTransportCCTSupport (~> 1.3)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- nanopb (~> 0.3.901)
|
||||
- FirebaseCoreDiagnosticsInterop (1.2.0)
|
||||
- FirebaseInstallations (1.1.0):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (4.3.0):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstallations (~> 1.0)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- Folly (2018.10.22.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
|
@ -73,51 +79,52 @@ PODS:
|
|||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (6.1.1):
|
||||
- GoogleAppMeasurement (6.2.2):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (~> 0.3)
|
||||
- GoogleDataTransport (1.2.0)
|
||||
- GoogleDataTransportCCTSupport (1.0.4):
|
||||
- GoogleDataTransport (~> 1.2)
|
||||
- nanopb
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.3.0):
|
||||
- nanopb (= 0.3.9011)
|
||||
- GoogleDataTransport (3.3.1)
|
||||
- GoogleDataTransportCCTSupport (1.3.1):
|
||||
- GoogleDataTransport (~> 3.3)
|
||||
- nanopb (~> 0.3.901)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.5.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.3.0)
|
||||
- GoogleUtilities/Logger (6.3.0):
|
||||
- GoogleUtilities/Environment (6.5.1)
|
||||
- GoogleUtilities/Logger (6.5.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (6.3.0):
|
||||
- GoogleUtilities/MethodSwizzler (6.5.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (6.3.0):
|
||||
- GoogleUtilities/Network (6.5.1):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.3.0)"
|
||||
- GoogleUtilities/Reachability (6.3.0):
|
||||
- "GoogleUtilities/NSData+zlib (6.5.1)"
|
||||
- GoogleUtilities/Reachability (6.5.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.3.0):
|
||||
- GoogleUtilities/UserDefaults (6.5.1):
|
||||
- GoogleUtilities/Logger
|
||||
- JitsiMeetSDK (2.4.0)
|
||||
- KeyCommands (2.0.3):
|
||||
- React
|
||||
- libwebp (1.0.3):
|
||||
- libwebp/demux (= 1.0.3)
|
||||
- libwebp/mux (= 1.0.3)
|
||||
- libwebp/webp (= 1.0.3)
|
||||
- libwebp/demux (1.0.3):
|
||||
- libwebp (1.1.0):
|
||||
- libwebp/demux (= 1.1.0)
|
||||
- libwebp/mux (= 1.1.0)
|
||||
- libwebp/webp (= 1.1.0)
|
||||
- libwebp/demux (1.1.0):
|
||||
- libwebp/webp
|
||||
- libwebp/mux (1.0.3):
|
||||
- libwebp/mux (1.1.0):
|
||||
- libwebp/demux
|
||||
- libwebp/webp (1.0.3)
|
||||
- nanopb (0.3.901):
|
||||
- nanopb/decode (= 0.3.901)
|
||||
- nanopb/encode (= 0.3.901)
|
||||
- nanopb/decode (0.3.901)
|
||||
- nanopb/encode (0.3.901)
|
||||
- libwebp/webp (1.1.0)
|
||||
- nanopb (0.3.9011):
|
||||
- nanopb/decode (= 0.3.9011)
|
||||
- nanopb/encode (= 0.3.9011)
|
||||
- nanopb/decode (0.3.9011)
|
||||
- nanopb/encode (0.3.9011)
|
||||
- PromisesObjC (1.2.8)
|
||||
- RCTRequired (0.61.5)
|
||||
- RCTTypeSafety (0.61.5):
|
||||
- FBLazyVector (= 0.61.5)
|
||||
|
@ -395,10 +402,10 @@ PODS:
|
|||
- RNVectorIcons (6.6.0):
|
||||
- React
|
||||
- RSKImageCropper (2.2.3)
|
||||
- SDWebImage (5.1.1):
|
||||
- SDWebImage/Core (= 5.1.1)
|
||||
- SDWebImage/Core (5.1.1)
|
||||
- SDWebImageWebPCoder (0.2.4):
|
||||
- SDWebImage (5.5.2):
|
||||
- SDWebImage/Core (= 5.5.2)
|
||||
- SDWebImage/Core (5.5.2)
|
||||
- SDWebImageWebPCoder (0.2.5):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.0)
|
||||
- UMBarCodeScannerInterface (3.0.0)
|
||||
|
@ -500,7 +507,7 @@ DEPENDENCIES:
|
|||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
trunk:
|
||||
- boost-for-react-native
|
||||
- Crashlytics
|
||||
- Fabric
|
||||
|
@ -509,6 +516,7 @@ SPEC REPOS:
|
|||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCoreDiagnosticsInterop
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
|
@ -516,6 +524,7 @@ SPEC REPOS:
|
|||
- GoogleUtilities
|
||||
- libwebp
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- RSKImageCropper
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
|
@ -713,22 +722,24 @@ SPEC CHECKSUMS:
|
|||
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
||||
FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f
|
||||
FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75
|
||||
Firebase: 9cbe4e5b5eaafa05dc932be58b7c8c3820d71e88
|
||||
FirebaseAnalytics: 843c7f64a8f9c79f0d03281197ebe7bb1d58d477
|
||||
FirebaseCore: e9d9bd1dae61c1e82bc1e0e617a9d832392086a0
|
||||
FirebaseCoreDiagnostics: 4c04ae09d0ab027c30179828c6bb47764df1bd13
|
||||
FirebaseCoreDiagnosticsInterop: 6829da2b8d1fc795ff1bd99df751d3788035d2cb
|
||||
FirebaseInstanceID: 550df9be1f99f751d8fcde3ac342a1e21a0e6c42
|
||||
Firebase: 497158b816d0a86fc31babbd05546fcd7e6083ff
|
||||
FirebaseAnalytics: cf95d3aab897612783020fbd98401d5366f135ee
|
||||
FirebaseCore: 85064903ed6c28e47fec9c7bd149d94ba1b6b6e7
|
||||
FirebaseCoreDiagnostics: 5e78803ab276bc5b50340e3c539c06c3de35c649
|
||||
FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
|
||||
FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b
|
||||
FirebaseInstanceID: 6668efc1655a4052c083f287a7141f1ead12f9c2
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
GoogleAppMeasurement: 86a82f0e1f20b8eedf8e20326530138fd71409de
|
||||
GoogleDataTransport: 8f9897b8e073687f24ca8d3c3a8013dec7d2d1cc
|
||||
GoogleDataTransportCCTSupport: 7455d07b98851aa63e4c05a34dad356ca588479e
|
||||
GoogleUtilities: 9c2c544202301110b29f7974a82e77fdcf12bf51
|
||||
GoogleAppMeasurement: d0560d915abf15e692e8538ba1d58442217b6aff
|
||||
GoogleDataTransport: 0048df6388dab1c254799f2a30365b1dffe20422
|
||||
GoogleDataTransportCCTSupport: f880d70972efa2ed1be4e9173a0f4c5f3dc2d176
|
||||
GoogleUtilities: 06eb53bb579efe7099152735900dd04bf09e7275
|
||||
JitsiMeetSDK: d4a3aeed1a75fd57e6a78e5d202b6051dfcb9320
|
||||
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
||||
libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e
|
||||
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
|
||||
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
||||
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
|
||||
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
|
||||
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
||||
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
||||
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
||||
|
@ -778,8 +789,8 @@ SPEC CHECKSUMS:
|
|||
RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6
|
||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||
SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8
|
||||
SDWebImageWebPCoder: cc72085bb20368b2f8dbb21b7e355c667e1309b7
|
||||
SDWebImage: 4d5c027c935438f341ed33dbac53ff9f479922ca
|
||||
SDWebImageWebPCoder: 947093edd1349d820c40afbd9f42acb6cdecd987
|
||||
UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
|
||||
UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
|
||||
UMConstantsInterface: 038bacb19de12b6fd328c589122c8dc977cccf61
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <FirebaseCore/FirebaseCore.h>
|
||||
|
||||
#if !defined(__has_include)
|
||||
|
@ -12,6 +26,10 @@
|
|||
#import <FirebaseAuth/FirebaseAuth.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<FirebaseCrashlytics/FirebaseCrashlytics.h>)
|
||||
#import <FirebaseCrashlytics/FirebaseCrashlytics.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<FirebaseDatabase/FirebaseDatabase.h>)
|
||||
#import <FirebaseDatabase/FirebaseDatabase.h>
|
||||
#endif
|
||||
|
|
|
@ -1,93 +1,254 @@
|
|||
# Firebase APIs for iOS
|
||||
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||
|
||||
Simplify your iOS development, grow your user base, and monetize more
|
||||
effectively with Firebase services.
|
||||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||
FirebaseStorage.
|
||||
|
||||
Much more information can be found at [https://firebase.google.com](https://firebase.google.com).
|
||||
The repository also includes GoogleUtilities source. The
|
||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||
a set of utilities used by Firebase and other Google products.
|
||||
|
||||
## Install a Firebase SDK using CocoaPods
|
||||
Firebase is an app development platform with tools to help you build, grow and
|
||||
monetize your app. More information about Firebase can be found at
|
||||
[https://firebase.google.com](https://firebase.google.com).
|
||||
|
||||
Firebase distributes several iOS specific APIs and SDKs via CocoaPods.
|
||||
You can install the CocoaPods tool on OS X by running the following command from
|
||||
the terminal. Detailed information is available in the [Getting Started
|
||||
guide](https://guides.cocoapods.org/using/getting-started.html#getting-started).
|
||||
## Installation
|
||||
|
||||
See the three subsections for details about three different installation methods.
|
||||
1. [Standard pod install](README.md#standard-pod-install)
|
||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||
|
||||
### Standard pod install
|
||||
|
||||
Go to
|
||||
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||
|
||||
### Installing from GitHub
|
||||
|
||||
For releases starting with 5.0.0, the source for each release is also deployed
|
||||
to CocoaPods master and available via standard
|
||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||
|
||||
These instructions can be used to access the Firebase repo at other branches,
|
||||
tags, or commits.
|
||||
|
||||
#### Background
|
||||
|
||||
See
|
||||
[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
|
||||
for instructions and options about overriding pod source locations.
|
||||
|
||||
#### Accessing Firebase Source Snapshots
|
||||
|
||||
All of the official releases are tagged in this repo and available via CocoaPods. To access a local
|
||||
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||
|
||||
To access FirebaseFirestore via a branch:
|
||||
```
|
||||
$ sudo gem install cocoapods
|
||||
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||
```
|
||||
|
||||
## Try out an SDK
|
||||
|
||||
You can try any of the SDKs with `pod try`. Run the following command and select
|
||||
the SDK you are interested in when prompted:
|
||||
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||
|
||||
```
|
||||
$ pod try Firebase
|
||||
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||
```
|
||||
|
||||
Note that some SDKs may require credentials. More information is available in
|
||||
the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/).
|
||||
### Carthage (iOS only)
|
||||
|
||||
## Add a Firebase SDK to your iOS app
|
||||
Instructions for the experimental Carthage distribution are at
|
||||
[Carthage](Carthage.md).
|
||||
|
||||
CocoaPods is used to install and manage dependencies in existing Xcode projects.
|
||||
### Rome
|
||||
|
||||
1. Create an Xcode project, and save it to your local machine.
|
||||
2. Create a file named `Podfile` in your project directory. This file defines
|
||||
your project's dependencies, and is commonly referred to as a Podspec.
|
||||
3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here:
|
||||
Instructions for installing binary frameworks via
|
||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||
|
||||
```
|
||||
platform :ios, '8.0'
|
||||
pod 'Firebase'
|
||||
```
|
||||
## Development
|
||||
|
||||
4. Save the file.
|
||||
To develop Firebase software in this repository, ensure that you have at least
|
||||
the following software:
|
||||
|
||||
5. Open a terminal and `cd` to the directory containing the Podfile.
|
||||
* Xcode 10.1 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||
|
||||
```
|
||||
$ cd <path-to-project>/project/
|
||||
```
|
||||
For the pod that you want to develop:
|
||||
|
||||
6. Run the `pod install` command. This will install the SDKs specified in the
|
||||
Podspec, along with any dependencies they may have.
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
|
||||
```
|
||||
$ pod install
|
||||
```
|
||||
Note: If the CocoaPods cache is out of date, you may need to run
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
||||
7. Open your app's `.xcworkspace` file to launch Xcode. Use this file for all
|
||||
development on your app.
|
||||
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
|
||||
those platforms. Since 10.2, Xcode does not properly handle multi-platform
|
||||
CocoaPods workspaces.
|
||||
|
||||
8. You can also install other Firebase SDKs by adding the subspecs in the
|
||||
Podfile.
|
||||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
```
|
||||
pod 'Firebase/AdMob'
|
||||
pod 'Firebase/Analytics'
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/DynamicLinks'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Functions'
|
||||
pod 'Firebase/InAppMessaging'
|
||||
pod 'Firebase/InAppMessagingDisplay'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/MLCommon'
|
||||
pod 'Firebase/MLModelInterpreter'
|
||||
pod 'Firebase/MLNLLanguageID'
|
||||
pod 'Firebase/MLNLSmartReply'
|
||||
pod 'Firebase/MLNLTranslate'
|
||||
pod 'Firebase/MLNaturalLanguage'
|
||||
pod 'Firebase/MLVision'
|
||||
pod 'Firebase/MLVisionAutoML'
|
||||
pod 'Firebase/MLVisionBarcodeModel'
|
||||
pod 'Firebase/MLVisionFaceModel'
|
||||
pod 'Firebase/MLVisionLabelModel'
|
||||
pod 'Firebase/MLVisionObjectDetection'
|
||||
pod 'Firebase/MLVisionTextModel'
|
||||
pod 'Firebase/Performance'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
```
|
||||
### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* Sign the App in the Settings Signing & Capabilities tab
|
||||
* Click Pods in the Project Manager
|
||||
* Add Signing to the iOS host app and unit test targets
|
||||
* Select the Unit-unit scheme
|
||||
* Run it to build and test
|
||||
|
||||
### Adding a New Firebase Pod
|
||||
|
||||
See [AddNewPod.md](AddNewPod.md).
|
||||
|
||||
### Code Formatting
|
||||
|
||||
To ensure that the code is formatted consistently, run the script
|
||||
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
||||
before creating a PR.
|
||||
|
||||
Travis will verify that any code changes are done in a style compliant way. Install
|
||||
`clang-format` and `swiftformat`.
|
||||
These commands will get the right versions:
|
||||
|
||||
```
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
|
||||
```
|
||||
|
||||
Note: if you already have a newer version of these installed you may need to
|
||||
`brew switch` to this version.
|
||||
|
||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
||||
match the versions in the CI failure logs
|
||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||
|
||||
#### Viewing Code Coverage
|
||||
|
||||
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
||||
|
||||
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
||||
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
||||
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
||||
|
||||
### Running Sample Apps
|
||||
In order to run the sample apps and integration tests, you'll need valid
|
||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||
files without real values, but can be replaced with real plist files. To get your own
|
||||
`GoogleService-Info.plist` files:
|
||||
|
||||
1. Go to the [Firebase Console](https://console.firebase.google.com/)
|
||||
2. Create a new Firebase project, if you don't already have one
|
||||
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||
identifier (e.g. `com.google.Database-Example`)
|
||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||
|
||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
||||
identifier that you can control in your own Apple Developer account.
|
||||
|
||||
## Specific Component Instructions
|
||||
See the sections below for any special instructions for those components.
|
||||
|
||||
### Firebase Auth
|
||||
|
||||
If you're doing specific Firebase Auth development, see
|
||||
[the Auth Sample README](Example/Auth/README.md) for instructions about
|
||||
building and running the FirebaseAuth pod along with various samples and tests.
|
||||
|
||||
### Firebase Database
|
||||
|
||||
To run the Database Integration tests, make your database authentication rules
|
||||
[public](https://firebase.google.com/docs/database/security/quickstart).
|
||||
|
||||
### Firebase Storage
|
||||
|
||||
To run the Storage Integration tests, follow the instructions in
|
||||
[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m).
|
||||
|
||||
#### Push Notifications
|
||||
|
||||
Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
|
||||
In order to actually test receiving push notifications, you will need to:
|
||||
|
||||
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||
account, and enable that App ID for push notifications.
|
||||
2. You'll also need to
|
||||
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||
|
||||
#### iOS Simulator
|
||||
|
||||
The iOS Simulator cannot register for remote notifications, and will not receive push notifications.
|
||||
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||
physical device.
|
||||
|
||||
## Community Supported Efforts
|
||||
|
||||
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||
participate in the Firebase community.
|
||||
|
||||
### tvOS, macOS, and Catalyst
|
||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||
tvOS, macOS, and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
|
||||
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
During app setup in the console, you may get to a step that mentions something like "Checking if the app
|
||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/Catalyst.
|
||||
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
||||
|
||||
To install, add a subset of the following to the Podfile:
|
||||
|
||||
```
|
||||
pod 'Firebase/ABTesting'
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Crashlytics'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Functions'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
```
|
||||
|
||||
#### Additional Catalyst Notes
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
to Build Settings.
|
||||
* FirebaseFirestore requires signing the
|
||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||
plans and directions.
|
||||
|
||||
## Contributing
|
||||
|
||||
See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
|
||||
iOS SDK.
|
||||
|
||||
## License
|
||||
|
||||
The contents of this repository is licensed under the
|
||||
[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
Your use of Firebase is governed by the
|
||||
[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -9,6 +9,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/// The top level Firebase Analytics singleton that provides methods for logging events and setting
|
||||
/// user properties. See <a href="http://goo.gl/gz8SLz">the developer guides</a> for general
|
||||
/// information on using Firebase Analytics in your apps.
|
||||
///
|
||||
/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling
|
||||
/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in
|
||||
/// unexpected crashes at runtime.
|
||||
NS_SWIFT_NAME(Analytics)
|
||||
@interface FIRAnalytics : NSObject
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "Private/FIRAnalyticsConfiguration.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
|
@ -22,17 +22,22 @@
|
|||
#import <AppKit/AppKit.h>
|
||||
#endif
|
||||
|
||||
#import "FIRApp.h"
|
||||
#import <FirebaseCore/FIRApp.h>
|
||||
|
||||
#import "Private/FIRAnalyticsConfiguration.h"
|
||||
#import "Private/FIRAppInternal.h"
|
||||
#import "Private/FIRBundleUtil.h"
|
||||
#import "Private/FIRComponentContainerInternal.h"
|
||||
#import "Private/FIRConfigurationInternal.h"
|
||||
#import "Private/FIRCoreDiagnosticsConnector.h"
|
||||
#import "Private/FIRLibrary.h"
|
||||
#import "Private/FIRLogger.h"
|
||||
#import "Private/FIROptionsInternal.h"
|
||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainerInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRConfigurationInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
// The kFIRService strings are only here while transitioning CoreDiagnostics from the Analytics
|
||||
// pod to a Core dependency. These symbols are not used and should be deleted after the transition.
|
||||
|
@ -111,6 +116,7 @@ static NSMutableArray<Class<FIRLibrary>> *sRegisteredAsConfigurable;
|
|||
static NSMutableDictionary *sAllApps;
|
||||
static FIRApp *sDefaultApp;
|
||||
static NSMutableDictionary *sLibraryVersions;
|
||||
static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||
|
||||
+ (void)configure {
|
||||
FIROptions *options = [FIROptions defaultOptions];
|
||||
|
@ -159,8 +165,9 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
|
||||
if ([name isEqualToString:kFIRDefaultAppName]) {
|
||||
if (sDefaultApp) {
|
||||
[NSException raise:kFirebaseCoreErrorDomain
|
||||
format:@"Default app has already been configured."];
|
||||
// The default app already exixts. Handle duplicate `configure` calls and return.
|
||||
[self appWasConfiguredTwice:sDefaultApp usingOptions:options];
|
||||
return;
|
||||
}
|
||||
|
||||
FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app.");
|
||||
|
@ -176,8 +183,9 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
|
||||
@synchronized(self) {
|
||||
if (sAllApps && sAllApps[name]) {
|
||||
[NSException raise:kFirebaseCoreErrorDomain
|
||||
format:@"App named %@ has already been configured.", name];
|
||||
// The app already exists. Handle a duplicate `configure` call and return.
|
||||
[self appWasConfiguredTwice:sAllApps[name] usingOptions:options];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,10 +199,44 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
}
|
||||
|
||||
[FIRApp addAppToAppDictionary:app];
|
||||
|
||||
// The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be
|
||||
// instantiated.
|
||||
[app.container instantiateEagerComponents];
|
||||
[FIRApp sendNotificationsToSDKs:app];
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when `configure` has been called multiple times for the same app. This can either throw
|
||||
/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed
|
||||
/// like an extension.
|
||||
+ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options {
|
||||
// Only extensions should potentially be able to call `configure` more than once.
|
||||
if (![GULAppEnvironmentUtil isAppExtension]) {
|
||||
// Throw an exception since this is now an invalid state.
|
||||
if (app.isDefaultApp) {
|
||||
[NSException raise:kFirebaseCoreErrorDomain
|
||||
format:@"Default app has already been configured."];
|
||||
} else {
|
||||
[NSException raise:kFirebaseCoreErrorDomain
|
||||
format:@"App named %@ has already been configured.", app.name];
|
||||
}
|
||||
}
|
||||
|
||||
// In an extension, the entry point could be called multiple times. As long as the options are
|
||||
// identical we should allow multiple `configure` calls.
|
||||
if ([options isEqual:app.options]) {
|
||||
// Everything is identical but the extension's lifecycle triggered `configure` twice.
|
||||
// Ignore duplicate calls and return since everything should still be in a valid state.
|
||||
FIRLogDebug(kFIRLoggerCore, @"I-COR000035",
|
||||
@"Ignoring second `configure` call in an extension.");
|
||||
return;
|
||||
} else {
|
||||
[NSException raise:kFirebaseCoreErrorDomain
|
||||
format:@"App named %@ has already been configured.", app.name];
|
||||
}
|
||||
}
|
||||
|
||||
+ (FIRApp *)defaultApp {
|
||||
if (sDefaultApp) {
|
||||
return sDefaultApp;
|
||||
|
@ -236,6 +278,7 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
sAllApps = nil;
|
||||
[sLibraryVersions removeAllObjects];
|
||||
sLibraryVersions = nil;
|
||||
sFirebaseUserAgentOnceToken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +395,7 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
}
|
||||
|
||||
// Check if the Analytics flag is explicitly set. If so, no further actions are necessary.
|
||||
if ([self.options isAnalyticsCollectionExpicitlySet]) {
|
||||
if ([self.options isAnalyticsCollectionExplicitlySet]) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -517,6 +560,25 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
|
||||
+ (NSString *)firebaseUserAgent {
|
||||
@synchronized(self) {
|
||||
dispatch_once(&sFirebaseUserAgentOnceToken, ^{
|
||||
// Report FirebaseCore version for useragent string
|
||||
[FIRApp registerLibrary:@"fire-ios"
|
||||
withVersion:[NSString stringWithUTF8String:FIRCoreVersionString]];
|
||||
|
||||
NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *xcodeVersion = info[@"DTXcodeBuild"];
|
||||
NSString *sdkVersion = info[@"DTSDKBuild"];
|
||||
if (xcodeVersion) {
|
||||
[FIRApp registerLibrary:@"xcode" withVersion:xcodeVersion];
|
||||
}
|
||||
if (sdkVersion) {
|
||||
[FIRApp registerLibrary:@"apple-sdk" withVersion:sdkVersion];
|
||||
}
|
||||
|
||||
NSString *swiftFlagValue = [self hasSwiftRuntime] ? @"true" : @"false";
|
||||
[FIRApp registerLibrary:@"swift" withVersion:swiftFlagValue];
|
||||
});
|
||||
|
||||
NSMutableArray<NSString *> *libraries =
|
||||
[[NSMutableArray<NSString *> alloc] initWithCapacity:sLibraryVersions.count];
|
||||
for (NSString *libraryName in sLibraryVersions) {
|
||||
|
@ -528,6 +590,20 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
}
|
||||
}
|
||||
|
||||
+ (BOOL)hasSwiftRuntime {
|
||||
// The class
|
||||
// [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35)
|
||||
// is a part of Swift runtime, so it should be present if Swift runtime is available.
|
||||
|
||||
BOOL hasSwiftRuntime =
|
||||
objc_lookUpClass("Swift._SwiftObject") != nil ||
|
||||
// Swift object class name before
|
||||
// https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01
|
||||
objc_getClass("_TtCs12_SwiftObject") != nil;
|
||||
|
||||
return hasSwiftRuntime;
|
||||
}
|
||||
|
||||
- (void)checkExpectedBundleID {
|
||||
NSArray *bundles = [FIRBundleUtil relevantBundles];
|
||||
NSString *expectedBundleID = [self expectedBundleID];
|
||||
|
@ -811,16 +887,16 @@ static NSMutableDictionary *sLibraryVersions;
|
|||
- (void)subscribeForAppDidBecomeActiveNotifications {
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification;
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
#elif TARGET_OS_OSX
|
||||
NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification;
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_WATCH
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(appDidBecomeActive:)
|
||||
name:notificationName
|
||||
object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appDidBecomeActive:(NSNotification *)notification {
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRAppAssociationRegistration.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppAssociationRegistration.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRBundleUtil.h"
|
||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRComponent.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||
|
||||
#import "Private/FIRComponentContainer.h"
|
||||
#import "Private/FIRDependency.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||
|
||||
@interface FIRComponent ()
|
||||
|
|
@ -14,26 +14,27 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRComponentContainer.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||
|
||||
#import "Private/FIRAppInternal.h"
|
||||
#import "Private/FIRComponent.h"
|
||||
#import "Private/FIRLibrary.h"
|
||||
#import "Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FIRComponentContainer () {
|
||||
dispatch_queue_t _containerQueue;
|
||||
}
|
||||
@interface FIRComponentContainer ()
|
||||
|
||||
/// The dictionary of components that are registered for a particular app. The key is an NSString
|
||||
/// The dictionary of components that are registered for a particular app. The key is an `NSString`
|
||||
/// of the protocol.
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRComponentCreationBlock> *components;
|
||||
|
||||
/// Cached instances of components that requested to be cached.
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSString *, id> *cachedInstances;
|
||||
|
||||
/// Protocols of components that have requested to be eagerly instantiated.
|
||||
@property(nonatomic, strong, nullable) NSMutableArray<Protocol *> *eagerProtocolsToInstantiate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRComponentContainer
|
||||
|
@ -69,8 +70,6 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
_app = app;
|
||||
_cachedInstances = [NSMutableDictionary<NSString *, id> dictionary];
|
||||
_components = [NSMutableDictionary<NSString *, FIRComponentCreationBlock> dictionary];
|
||||
_containerQueue =
|
||||
dispatch_queue_create("com.google.FirebaseComponentContainer", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
[self populateComponentsFromRegisteredClasses:allRegistrants forApp:app];
|
||||
}
|
||||
|
@ -78,6 +77,9 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
}
|
||||
|
||||
- (void)populateComponentsFromRegisteredClasses:(NSSet<Class> *)classes forApp:(FIRApp *)app {
|
||||
// Keep track of any components that need to eagerly instantiate after all components are added.
|
||||
self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init];
|
||||
|
||||
// Loop through the verified component registrants and populate the components array.
|
||||
for (Class<FIRLibrary> klass in classes) {
|
||||
// Loop through all the components being registered and store them as appropriate.
|
||||
|
@ -96,14 +98,16 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
// Store the creation block for later usage.
|
||||
self.components[protocolName] = component.creationBlock;
|
||||
|
||||
// Instantiate the instance if it has requested to be instantiated.
|
||||
// Queue any protocols that should be eagerly instantiated. Don't instantiate them yet
|
||||
// because they could depend on other components that haven't been added to the components
|
||||
// array yet.
|
||||
BOOL shouldInstantiateEager =
|
||||
(component.instantiationTiming == FIRInstantiationTimingAlwaysEager);
|
||||
BOOL shouldInstantiateDefaultEager =
|
||||
(component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp &&
|
||||
[app isDefaultApp]);
|
||||
if (shouldInstantiateEager || shouldInstantiateDefaultEager) {
|
||||
[self instantiateInstanceForProtocol:component.protocol withBlock:component.creationBlock];
|
||||
[self.eagerProtocolsToInstantiate addObject:component.protocol];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,11 +115,28 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
|
||||
#pragma mark - Instance Creation
|
||||
|
||||
- (void)instantiateEagerComponents {
|
||||
// After all components are registered, instantiate the ones that are requesting eager
|
||||
// instantiation.
|
||||
@synchronized(self) {
|
||||
for (Protocol *protocol in self.eagerProtocolsToInstantiate) {
|
||||
// Get an instance for the protocol, which will instantiate it since it couldn't have been
|
||||
// cached yet. Ignore the instance coming back since we don't need it.
|
||||
__unused id unusedInstance = [self instanceForProtocol:protocol];
|
||||
}
|
||||
|
||||
// All eager instantiation is complete, clear the stored property now.
|
||||
self.eagerProtocolsToInstantiate = nil;
|
||||
}
|
||||
}
|
||||
|
||||
/// Instantiate an instance of a class that conforms to the specified protocol.
|
||||
/// This will:
|
||||
/// - Call the block to create an instance if possible,
|
||||
/// - Validate that the instance returned conforms to the protocol it claims to,
|
||||
/// - Cache the instance if the block requests it
|
||||
///
|
||||
/// Note that this method assumes the caller already has @sychronized on self.
|
||||
- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol
|
||||
withBlock:(FIRComponentCreationBlock)creationBlock {
|
||||
if (!creationBlock) {
|
||||
|
@ -140,9 +161,7 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
|
||||
// The instance is ready to be returned, but check if it should be cached first before returning.
|
||||
if (shouldCache) {
|
||||
dispatch_sync(_containerQueue, ^{
|
||||
self.cachedInstances[protocolName] = instance;
|
||||
});
|
||||
self.cachedInstances[protocolName] = instance;
|
||||
}
|
||||
|
||||
return instance;
|
||||
|
@ -153,47 +172,35 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
|||
- (nullable id)instanceForProtocol:(Protocol *)protocol {
|
||||
// Check if there is a cached instance, and return it if so.
|
||||
NSString *protocolName = NSStringFromProtocol(protocol);
|
||||
__block id cachedInstance;
|
||||
dispatch_sync(_containerQueue, ^{
|
||||
|
||||
id cachedInstance;
|
||||
@synchronized(self) {
|
||||
cachedInstance = self.cachedInstances[protocolName];
|
||||
});
|
||||
|
||||
if (cachedInstance) {
|
||||
return cachedInstance;
|
||||
if (!cachedInstance) {
|
||||
// Use the creation block to instantiate an instance and return it.
|
||||
FIRComponentCreationBlock creationBlock = self.components[protocolName];
|
||||
cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock];
|
||||
}
|
||||
}
|
||||
|
||||
// Use the creation block to instantiate an instance and return it.
|
||||
FIRComponentCreationBlock creationBlock = self.components[protocolName];
|
||||
return [self instantiateInstanceForProtocol:protocol withBlock:creationBlock];
|
||||
return cachedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)removeAllCachedInstances {
|
||||
// Loop through the cache and notify each instance that is a maintainer to clean up after itself.
|
||||
// Design note: we're getting a copy here, unlocking the cached instances, iterating over the
|
||||
// copy, then locking and removing all cached instances. A race condition *could* exist where a
|
||||
// new cached instance is created between the copy and the removal, but the chances are slim and
|
||||
// side-effects are significantly smaller than including the entire loop in the `dispatch_sync`
|
||||
// block (access to the cache from inside the block would deadlock and crash).
|
||||
__block NSDictionary<NSString *, id> *instancesCopy;
|
||||
dispatch_sync(_containerQueue, ^{
|
||||
instancesCopy = [self.cachedInstances copy];
|
||||
});
|
||||
|
||||
for (id instance in instancesCopy.allValues) {
|
||||
if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] &&
|
||||
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
||||
[instance appWillBeDeleted:self.app];
|
||||
@synchronized(self) {
|
||||
// Loop through the cache and notify each instance that is a maintainer to clean up after
|
||||
// itself.
|
||||
for (id instance in self.cachedInstances.allValues) {
|
||||
if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] &&
|
||||
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
||||
[instance appWillBeDeleted:self.app];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instancesCopy = nil;
|
||||
|
||||
// Empty the cache.
|
||||
dispatch_sync(_containerQueue, ^{
|
||||
// Empty the cache.
|
||||
[self.cachedInstances removeAllObjects];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRComponentType.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentType.h"
|
||||
|
||||
#import "Private/FIRComponentContainerInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainerInternal.h"
|
||||
|
||||
@implementation FIRComponentType
|
||||
|
|
@ -12,9 +12,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRConfigurationInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRConfigurationInternal.h"
|
||||
|
||||
#import "Private/FIRAnalyticsConfiguration.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h"
|
||||
|
||||
extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
|
||||
|
|
@ -14,15 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRCoreDiagnosticsConnector.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
||||
|
||||
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsInterop.h>
|
||||
|
||||
#import <FirebaseCore/FIROptions.h>
|
||||
|
||||
#import "Private/FIRAppInternal.h"
|
||||
#import "Private/FIRDiagnosticsData.h"
|
||||
#import "Private/FIROptionsInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
|
||||
// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop.
|
||||
Class<FIRCoreDiagnosticsInterop> FIRCoreDiagnosticsImplementation;
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRDependency.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||
|
||||
@interface FIRDependency ()
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Private/FIRDiagnosticsData.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h"
|
||||
|
||||
#import <FirebaseCore/FIRApp.h>
|
||||
|
||||
#import "Private/FIRAppInternal.h"
|
||||
#import "Private/FIROptionsInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
|
||||
@implementation FIRDiagnosticsData {
|
||||
/** Backing ivar for the diagnosticObjects property. */
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRErrors.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRErrors.h"
|
||||
|
||||
NSString *const kFirebaseErrorDomain = @"com.firebase";
|
||||
NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config";
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||
#import <GoogleUtilities/GULLogger.h>
|
||||
|
||||
const static long secondsInDay = 864000;
|
||||
@implementation FIRHeartbeatInfo : NSObject
|
||||
|
||||
/** Updates the storage with the heartbeat information corresponding to this tag.
|
||||
* @param heartbeatTag Tag which could either be sdk specific tag or the global tag.
|
||||
* @return Boolean representing whether the heartbeat needs to be sent for this tag or not.
|
||||
*/
|
||||
+ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag {
|
||||
@synchronized(self) {
|
||||
NSString *const kHeartbeatStorageFile = @"HEARTBEAT_INFO_STORAGE";
|
||||
GULHeartbeatDateStorage *dataStorage =
|
||||
[[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageFile];
|
||||
NSDate *heartbeatTime = [dataStorage heartbeatDateForTag:heartbeatTag];
|
||||
NSDate *currentDate = [NSDate date];
|
||||
if (heartbeatTime != nil) {
|
||||
NSTimeInterval secondsBetween = [currentDate timeIntervalSinceDate:heartbeatTime];
|
||||
if (secondsBetween < secondsInDay) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return [dataStorage setHearbeatDate:currentDate forTag:heartbeatTag];
|
||||
}
|
||||
}
|
||||
|
||||
+ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag {
|
||||
NSString *globalTag = @"GLOBAL";
|
||||
BOOL isSdkHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:heartbeatTag];
|
||||
BOOL isGlobalHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:globalTag];
|
||||
if (!isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) {
|
||||
// Both sdk and global heartbeat not needed.
|
||||
return FIRHeartbeatInfoCodeNone;
|
||||
} else if (isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) {
|
||||
// Only SDK heartbeat needed.
|
||||
return FIRHeartbeatInfoCodeSDK;
|
||||
} else if (!isSdkHeartbeatNeeded && isGlobalHeartbeatNeeded) {
|
||||
// Only global heartbeat needed.
|
||||
return FIRHeartbeatInfoCodeGlobal;
|
||||
} else {
|
||||
// Both sdk and global heartbeat are needed.
|
||||
return FIRHeartbeatInfoCodeCombined;
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -12,13 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
|
||||
#import <FirebaseCore/FIRLoggerLevel.h>
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
#import <GoogleUtilities/GULLogger.h>
|
||||
|
||||
#import "Private/FIRVersion.h"
|
||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||
|
||||
FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]";
|
||||
|
|
@ -12,12 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Private/FIRAppInternal.h"
|
||||
#import "Private/FIRBundleUtil.h"
|
||||
#import "Private/FIRErrors.h"
|
||||
#import "Private/FIRLogger.h"
|
||||
#import "Private/FIROptionsInternal.h"
|
||||
#import "Private/FIRVersion.h"
|
||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
|
||||
// Keys for the strings in the plist file.
|
||||
NSString *const kFIRAPIKey = @"API_KEY";
|
||||
|
@ -110,22 +109,6 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
|
||||
#pragma mark - Private class methods
|
||||
|
||||
+ (void)initialize {
|
||||
// Report FirebaseCore version for useragent string
|
||||
[FIRApp registerLibrary:@"fire-ios"
|
||||
withVersion:[NSString stringWithUTF8String:FIRCoreVersionString]];
|
||||
|
||||
NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *xcodeVersion = info[@"DTXcodeBuild"];
|
||||
NSString *sdkVersion = info[@"DTSDKBuild"];
|
||||
if (xcodeVersion) {
|
||||
[FIRApp registerLibrary:@"xcode" withVersion:xcodeVersion];
|
||||
}
|
||||
if (sdkVersion) {
|
||||
[FIRApp registerLibrary:@"apple-sdk" withVersion:sdkVersion];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)defaultOptionsDictionary {
|
||||
if (sDefaultOptionsDictionary != nil) {
|
||||
return sDefaultOptionsDictionary;
|
||||
|
@ -346,6 +329,59 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
_appGroupID = [appGroupID copy];
|
||||
}
|
||||
|
||||
#pragma mark - Equality
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (!object || ![object isKindOfClass:[FIROptions class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [self isEqualToOptions:(FIROptions *)object];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToOptions:(FIROptions *)options {
|
||||
// Skip any non-FIROptions classes.
|
||||
if (![options isKindOfClass:[FIROptions class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Check the internal dictionary and custom properties for differences.
|
||||
if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Validate extra properties not contained in the dictionary. Only validate it if one of the
|
||||
// objects has the property set.
|
||||
if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) &&
|
||||
![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((options.appGroupID != nil || self.appGroupID != nil) &&
|
||||
![options.appGroupID isEqualToString:self.appGroupID]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Validate the Analytics options haven't changed with the Info.plist.
|
||||
if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since
|
||||
// those relate to lifecycle and construction, we only care if the contents of the options
|
||||
// themselves are equal.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
// This is strongly recommended for any object that implements a custom `isEqual:` method to
|
||||
// ensure that dictionary and set behavior matches other `isEqual:` checks.
|
||||
// Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the
|
||||
// contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents
|
||||
// should be identical.
|
||||
return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash;
|
||||
}
|
||||
|
||||
#pragma mark - Internal instance methods
|
||||
|
||||
- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary {
|
||||
|
@ -399,7 +435,7 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
return [value boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)isAnalyticsCollectionExpicitlySet {
|
||||
- (BOOL)isAnalyticsCollectionExplicitlySet {
|
||||
// If it's de-activated, it classifies as explicity set. If not, it's not a good enough indication
|
||||
// that the developer wants FirebaseAnalytics enabled so continue checking.
|
||||
if (self.isAnalyticsCollectionDeactivated) {
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FIRComponentType.h"
|
||||
#import "FIRLibrary.h"
|
||||
#import <FirebaseCore/FIRComponentType.h>
|
||||
#import <FirebaseCore/FIRLibrary.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FIRComponent.h"
|
||||
#import "FIRComponentContainer.h"
|
||||
#import <FirebaseCore/FIRComponent.h>
|
||||
#import <FirebaseCore/FIRComponentContainer.h>
|
||||
|
||||
@class FIRApp;
|
||||
|
||||
|
@ -24,13 +24,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface FIRComponentContainer (Private)
|
||||
|
||||
/// Initializes a contain for a given app. This should only be called by the app itself.
|
||||
/// Initializes a container for a given app. This should only be called by the app itself.
|
||||
- (instancetype)initWithApp:(FIRApp *)app;
|
||||
|
||||
/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the
|
||||
/// protocol wasn't registered, or if the instance couldn't instantiate for the provided app.
|
||||
/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app.
|
||||
- (nullable id)instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:));
|
||||
|
||||
/// Instantiates all the components that have registered as "eager" after initialization.
|
||||
- (void)instantiateEagerComponents;
|
||||
|
||||
/// Remove all of the cached instances stored and allow them to clean up after themselves.
|
||||
- (void)removeAllCachedInstances;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRConfiguration.h"
|
||||
#import <FirebaseCore/FIRConfiguration.h>
|
||||
|
||||
@class FIRAnalyticsConfiguration;
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FIRHeartbeatInfo : NSObject
|
||||
|
||||
// Enum representing the different heartbeat codes.
|
||||
typedef NS_ENUM(NSInteger, FIRHeartbeatInfoCode) {
|
||||
FIRHeartbeatInfoCodeNone = 0,
|
||||
FIRHeartbeatInfoCodeSDK = 1,
|
||||
FIRHeartbeatInfoCodeGlobal = 2,
|
||||
FIRHeartbeatInfoCodeCombined = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get heartbeat code requred for the sdk.
|
||||
* @param heartbeatTag String representing the sdk heartbeat tag.
|
||||
* @return Heartbeat code indicating whether or not an sdk/global heartbeat
|
||||
* needs to be sent
|
||||
*/
|
||||
+ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -18,7 +18,8 @@
|
|||
#define FIRLibrary_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FIRComponent.h"
|
||||
|
||||
#import <FirebaseCore/FIRComponent.h>
|
||||
|
||||
@class FIRApp;
|
||||
|
|
@ -65,7 +65,7 @@ extern NSString *const kServiceInfoFileType;
|
|||
* Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at
|
||||
* runtime.
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL isAnalyticsCollectionExpicitlySet;
|
||||
@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet;
|
||||
|
||||
/**
|
||||
* Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless
|
|
@ -3,7 +3,8 @@
|
|||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||
FirebaseStorage.
|
||||
|
||||
The repository also includes GoogleUtilities source. The
|
||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||
|
@ -75,14 +76,31 @@ the following software:
|
|||
|
||||
* Xcode 10.1 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||
|
||||
For the pod that you want to develop:
|
||||
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
|
||||
Note: If the CocoaPods cache is out of date, you may need to run
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
||||
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
|
||||
those platforms. Since 10.2, Xcode does not properly handle multi-platform
|
||||
CocoaPods workspaces.
|
||||
|
||||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* Sign the App in the Settings Signing & Capabilities tab
|
||||
* Click Pods in the Project Manager
|
||||
* Add Signing to the iOS host app and unit test targets
|
||||
* Select the Unit-unit scheme
|
||||
* Run it to build and test
|
||||
|
||||
### Adding a New Firebase Pod
|
||||
|
||||
See [AddNewPod.md](AddNewPod.md).
|
||||
|
@ -98,13 +116,17 @@ Travis will verify that any code changes are done in a style compliant way. Inst
|
|||
These commands will get the right versions:
|
||||
|
||||
```
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
|
||||
```
|
||||
|
||||
Note: if you already have a newer version of these installed you may need to
|
||||
`brew switch` to this version.
|
||||
|
||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
||||
match the versions in the CI failure logs
|
||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||
|
@ -177,34 +199,42 @@ We've seen an amazing amount of interest and contributions to improve the Fireba
|
|||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||
participate in the Firebase community.
|
||||
|
||||
### macOS and tvOS
|
||||
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||
FirebaseDatabase, FirebaseMessaging,
|
||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||
macOS and tvOS.
|
||||
### tvOS, macOS, and Catalyst
|
||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||
tvOS, macOS, and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
|
||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
Note that the Firebase pod is not available for macOS and tvOS.
|
||||
During app setup in the console, you may get to a step that mentions something like "Checking if the app
|
||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/Catalyst.
|
||||
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
||||
|
||||
To install, add a subset of the following to the Podfile:
|
||||
|
||||
```
|
||||
pod 'FirebaseABTesting'
|
||||
pod 'FirebaseAuth'
|
||||
pod 'FirebaseCore'
|
||||
pod 'FirebaseDatabase'
|
||||
pod 'FirebaseFirestore'
|
||||
pod 'FirebaseFunctions'
|
||||
pod 'FirebaseMessaging'
|
||||
pod 'FirebaseStorage'
|
||||
pod 'Firebase/ABTesting'
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Crashlytics'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Functions'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
```
|
||||
|
||||
#### Additional Catalyst Notes
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
to Build Settings.
|
||||
* FirebaseFirestore requires signing the
|
||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
#import <objc/runtime.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||
#import <GoogleDataTransport/GDTEvent.h>
|
||||
#import <GoogleDataTransport/GDTTargets.h>
|
||||
#import <GoogleDataTransport/GDTTransport.h>
|
||||
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
|
||||
#import <GoogleDataTransport/GDTCOREvent.h>
|
||||
#import <GoogleDataTransport/GDTCORTargets.h>
|
||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||
#import <GoogleUtilities/GULLogger.h>
|
||||
|
||||
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsData.h>
|
||||
|
@ -34,8 +35,6 @@
|
|||
|
||||
#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
||||
|
||||
#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h"
|
||||
|
||||
/** The logger service string to use when printing to the console. */
|
||||
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
||||
|
||||
|
@ -85,6 +84,7 @@ static NSString *const kFIRAppDiagnosticsConfigurationTypeKey =
|
|||
static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey";
|
||||
static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey";
|
||||
static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey";
|
||||
static NSString *const kFIRCoreDiagnosticsHeartbeatTag = @"FIRCoreDiagnostics";
|
||||
|
||||
/**
|
||||
* The file name to the recent heartbeat date.
|
||||
|
@ -92,7 +92,8 @@ static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKV
|
|||
NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE";
|
||||
|
||||
/**
|
||||
* @note This should implement the GDTEventDataObject protocol, but can't because of weak-linking.
|
||||
* @note This should implement the GDTCOREventDataObject protocol, but can't because of
|
||||
* weak-linking.
|
||||
*/
|
||||
@interface FIRCoreDiagnosticsLog : NSObject
|
||||
|
||||
|
@ -111,14 +112,14 @@ NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTIC
|
|||
return self;
|
||||
}
|
||||
|
||||
// Provided and required by the GDTEventDataObject protocol.
|
||||
// Provided and required by the GDTCOREventDataObject protocol.
|
||||
- (NSData *)transportBytes {
|
||||
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
||||
|
||||
// Encode 1 time to determine the size.
|
||||
if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for size: %s",
|
||||
PB_GET_ERROR(&sizestream));
|
||||
GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s",
|
||||
PB_GET_ERROR(&sizestream));
|
||||
}
|
||||
|
||||
// Encode a 2nd time to actually get the bytes from it.
|
||||
|
@ -126,8 +127,8 @@ NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTIC
|
|||
CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
|
||||
pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
|
||||
if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
|
||||
PB_GET_ERROR(&ostream));
|
||||
GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
|
||||
PB_GET_ERROR(&ostream));
|
||||
}
|
||||
CFDataSetLength(dataRef, ostream.bytes_written);
|
||||
|
||||
|
@ -149,10 +150,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue;
|
||||
|
||||
/** The transport object used to send data. */
|
||||
@property(nonatomic, readonly) GDTTransport *transport;
|
||||
@property(nonatomic, readonly) GDTCORTransport *transport;
|
||||
|
||||
/** The storage to store the date of the last sent heartbeat. */
|
||||
@property(nonatomic, readonly) FIRCoreDiagnosticsDateFileStorage *heartbeatDateStorage;
|
||||
@property(nonatomic, readonly) GULHeartbeatDateStorage *heartbeatDateStorage;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -170,24 +171,24 @@ NS_ASSUME_NONNULL_END
|
|||
}
|
||||
|
||||
- (instancetype)init {
|
||||
GDTTransport *transport = [[GDTTransport alloc] initWithMappingID:@"137"
|
||||
transformers:nil
|
||||
target:kGDTTargetCCT];
|
||||
GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"137"
|
||||
transformers:nil
|
||||
target:kGDTCORTargetFLL];
|
||||
|
||||
FIRCoreDiagnosticsDateFileStorage *dateStorage = [[FIRCoreDiagnosticsDateFileStorage alloc]
|
||||
initWithFileURL:[[self class] filePathURLWithName:kFIRCoreDiagnosticsHeartbeatDateFileName]];
|
||||
GULHeartbeatDateStorage *dateStorage =
|
||||
[[GULHeartbeatDateStorage alloc] initWithFileName:kFIRCoreDiagnosticsHeartbeatDateFileName];
|
||||
|
||||
return [self initWithTransport:transport heartbeatDateStorage:dateStorage];
|
||||
}
|
||||
|
||||
/** Initializer for unit tests.
|
||||
*
|
||||
* @param transport A `GDTTransport` instance which that be used to send event.
|
||||
* @param transport A `GDTCORTransport` instance which that be used to send event.
|
||||
* @param heartbeatDateStorage An instanse of date storage to track heartbeat sending.
|
||||
* @return Returns the initialized `FIRCoreDiagnostics` instance.
|
||||
*/
|
||||
- (instancetype)initWithTransport:(GDTTransport *)transport
|
||||
heartbeatDateStorage:(FIRCoreDiagnosticsDateFileStorage *)heartbeatDateStorage {
|
||||
- (instancetype)initWithTransport:(GDTCORTransport *)transport
|
||||
heartbeatDateStorage:(GULHeartbeatDateStorage *)heartbeatDateStorage {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_diagnosticsQueue =
|
||||
|
@ -198,37 +199,6 @@ NS_ASSUME_NONNULL_END
|
|||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - File path helpers
|
||||
|
||||
/** Returns the URL path of the file with name fileName under the Application Support folder for
|
||||
* local logging. Creates the Application Support folder if the folder doesn't exist.
|
||||
*
|
||||
* @return the URL path of the file with the name fileName in Application Support.
|
||||
*/
|
||||
+ (NSURL *)filePathURLWithName:(NSString *)fileName {
|
||||
@synchronized(self) {
|
||||
NSArray<NSString *> *paths =
|
||||
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
NSArray<NSString *> *components = @[ paths.lastObject, @"Google/FIRApp" ];
|
||||
NSString *directoryString = [NSString pathWithComponents:components];
|
||||
NSURL *directoryURL = [NSURL fileURLWithPath:directoryString];
|
||||
|
||||
NSError *error;
|
||||
if (![directoryURL checkResourceIsReachableAndReturnError:&error]) {
|
||||
// If fail creating the Application Support directory, return nil.
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtURL:directoryURL
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error]) {
|
||||
GULLogWarning(kFIRCoreDiagnostics, YES, @"I-COR100001",
|
||||
@"Unable to create internal state storage: %@", error);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return [directoryURL URLByAppendingPathComponent:fileName];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Metadata helpers
|
||||
|
||||
/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus,
|
||||
|
@ -374,7 +344,8 @@ void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfigu
|
|||
config->has_pod_name = 1;
|
||||
|
||||
if (!diagnosticObjects[kFIRCDllAppsCountKey]) {
|
||||
GDTLogError(GDTMCEGeneralError, @"%@", @"App count is a required value in the data dict.");
|
||||
GDTCORLogError(GDTCORMCEGeneralError, @"%@",
|
||||
@"App count is a required value in the data dict.");
|
||||
}
|
||||
config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue];
|
||||
config->has_app_count = 1;
|
||||
|
@ -635,8 +606,8 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
|||
FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config];
|
||||
|
||||
// Send the log as a telemetry event.
|
||||
GDTEvent *event = [self.transport eventForTransport];
|
||||
event.dataObject = (id<GDTEventDataObject>)log;
|
||||
GDTCOREvent *event = [self.transport eventForTransport];
|
||||
event.dataObject = (id<GDTCOREventDataObject>)log;
|
||||
[self.transport sendTelemetryEvent:event];
|
||||
});
|
||||
}
|
||||
|
@ -646,7 +617,8 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
|||
- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config {
|
||||
// Check if need to send a heartbeat.
|
||||
NSDate *currentDate = [NSDate date];
|
||||
NSDate *lastCheckin = [self.heartbeatDateStorage date];
|
||||
NSDate *lastCheckin =
|
||||
[self.heartbeatDateStorage heartbeatDateForTag:kFIRCoreDiagnosticsHeartbeatTag];
|
||||
if (lastCheckin) {
|
||||
// Ensure the previous checkin was on a different date in the past.
|
||||
if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) {
|
||||
|
@ -655,12 +627,7 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
|||
}
|
||||
|
||||
// Update heartbeat sent date.
|
||||
NSError *error;
|
||||
if (![self.heartbeatDateStorage setDate:currentDate error:&error]) {
|
||||
GULLogError(kFIRCoreDiagnostics, NO, @"I-COR100004", @"Unable to persist internal state: %@",
|
||||
error);
|
||||
}
|
||||
|
||||
[self.heartbeatDateStorage setHearbeatDate:currentDate forTag:kFIRCoreDiagnosticsHeartbeatTag];
|
||||
// Set the flag.
|
||||
config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE;
|
||||
config->has_sdk_name = 1;
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h"
|
||||
|
||||
@interface FIRCoreDiagnosticsDateFileStorage ()
|
||||
@property(nonatomic, readonly) NSURL *fileURL;
|
||||
@end
|
||||
|
||||
@implementation FIRCoreDiagnosticsDateFileStorage
|
||||
|
||||
- (instancetype)initWithFileURL:(NSURL *)fileURL {
|
||||
if (fileURL == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_fileURL = fileURL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)setDate:(nullable NSDate *)date error:(NSError **)outError {
|
||||
NSString *stringToSave = @"";
|
||||
|
||||
if (date != nil) {
|
||||
NSTimeInterval timestamp = [date timeIntervalSinceReferenceDate];
|
||||
stringToSave = [NSString stringWithFormat:@"%f", timestamp];
|
||||
}
|
||||
|
||||
return [stringToSave writeToURL:self.fileURL
|
||||
atomically:YES
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:outError];
|
||||
}
|
||||
|
||||
- (nullable NSDate *)date {
|
||||
NSString *timestampString = [NSString stringWithContentsOfURL:self.fileURL
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if (timestampString.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSTimeInterval timestamp = timestampString.doubleValue;
|
||||
return [NSDate dateWithTimeIntervalSinceReferenceDate:timestamp];
|
||||
}
|
||||
|
||||
@end
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.9.2 */
|
||||
/* Generated by nanopb-0.3.9.3 */
|
||||
|
||||
#include "firebasecore.nanopb.h"
|
||||
|
||||
|
@ -26,28 +26,19 @@
|
|||
|
||||
|
||||
|
||||
const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34] = {
|
||||
const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22] = {
|
||||
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, logs_proto_mobilesdk_ios_ICoreConfiguration, configuration_type, configuration_type, 0),
|
||||
PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, version_name, configuration_type, 0),
|
||||
PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_number, version_name, 0),
|
||||
PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_type, build_number, 0),
|
||||
PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, plist_version, build_type, 0),
|
||||
PB_FIELD( 6, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_enabled, plist_version, 0),
|
||||
PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, sdk_service_enabled, 0),
|
||||
PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, configuration_type, 0),
|
||||
PB_FIELD( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 0),
|
||||
PB_FIELD( 10, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_id, device_model, 0),
|
||||
PB_FIELD( 11, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, project_number, app_id, 0),
|
||||
PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, project_number, 0),
|
||||
PB_FIELD( 13, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, client_id, bundle_id, 0),
|
||||
PB_FIELD( 14, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, install, client_id, 0),
|
||||
PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, install, 0),
|
||||
PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, app_id, 0),
|
||||
PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, bundle_id, 0),
|
||||
PB_FIELD( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 0),
|
||||
PB_FIELD( 19, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_version, icore_version, 0),
|
||||
PB_FIELD( 20, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_name, sdk_version, 0),
|
||||
PB_FIELD( 21, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_count, sdk_name, 0),
|
||||
PB_FIELD( 22, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, os_version, app_count, 0),
|
||||
PB_FIELD( 23, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, itunes_id, os_version, 0),
|
||||
PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, itunes_id, 0),
|
||||
PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, os_version, 0),
|
||||
PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_version, 0),
|
||||
PB_FIELD( 26, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployed_in_app_store, use_default_app, 0),
|
||||
PB_FIELD( 27, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, dynamic_framework_count, deployed_in_app_store, 0),
|
||||
|
@ -55,11 +46,8 @@ const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34] = {
|
|||
PB_FIELD( 29, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_zip_file, apple_framework_version, 0),
|
||||
PB_FIELD( 30, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployment_type, using_zip_file, 0),
|
||||
PB_FIELD( 31, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, platform_info, deployment_type, 0),
|
||||
PB_FIELD( 32, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_extensions, platform_info, 0),
|
||||
PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, app_extensions, 0),
|
||||
PB_FIELD( 34, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_error_count, swizzling_enabled, 0),
|
||||
PB_FIELD( 35, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_warning_count, log_error_count, 0),
|
||||
PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, log_warning_count, 0),
|
||||
PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, platform_info, 0),
|
||||
PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, swizzling_enabled, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.3.9.2 */
|
||||
/* Generated by nanopb-0.3.9.3 */
|
||||
|
||||
#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||
#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||
|
@ -111,23 +111,11 @@ typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType {
|
|||
typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
||||
bool has_configuration_type;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType configuration_type;
|
||||
pb_bytes_array_t *version_name;
|
||||
bool has_build_number;
|
||||
int64_t build_number;
|
||||
bool has_build_type;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType build_type;
|
||||
pb_bytes_array_t *plist_version;
|
||||
pb_size_t sdk_service_enabled_count;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_enabled;
|
||||
pb_size_t sdk_service_installed_count;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed;
|
||||
pb_bytes_array_t *device_model;
|
||||
pb_bytes_array_t *app_id;
|
||||
bool has_project_number;
|
||||
int64_t project_number;
|
||||
pb_bytes_array_t *bundle_id;
|
||||
pb_bytes_array_t *client_id;
|
||||
pb_bytes_array_t *install;
|
||||
bool has_pod_name;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name;
|
||||
pb_bytes_array_t *icore_version;
|
||||
|
@ -137,7 +125,6 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
|||
bool has_app_count;
|
||||
int32_t app_count;
|
||||
pb_bytes_array_t *os_version;
|
||||
pb_bytes_array_t *itunes_id;
|
||||
pb_bytes_array_t *min_supported_ios_version;
|
||||
bool has_use_default_app;
|
||||
bool use_default_app;
|
||||
|
@ -151,14 +138,8 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
|||
bool has_deployment_type;
|
||||
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type;
|
||||
pb_bytes_array_t *platform_info;
|
||||
bool has_app_extensions;
|
||||
int64_t app_extensions;
|
||||
bool has_swizzling_enabled;
|
||||
bool swizzling_enabled;
|
||||
bool has_log_error_count;
|
||||
int32_t log_error_count;
|
||||
bool has_log_warning_count;
|
||||
int32_t log_warning_count;
|
||||
bool has_using_gdt;
|
||||
bool using_gdt;
|
||||
/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */
|
||||
|
@ -167,30 +148,21 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
|||
/* Default values for struct fields */
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0}
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_configuration_type_tag 1
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_version_name_tag 2
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_icore_version_tag 18
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_number_tag 3
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_type_tag 4
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_plist_version_tag 5
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_enabled_tag 6
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_installed_tag 7
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_device_model_tag 9
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_id_tag 10
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_project_number_tag 11
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_bundle_id_tag 12
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_client_id_tag 13
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_itunes_id_tag 23
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_min_supported_ios_version_tag 24
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_install_tag 14
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_use_default_app_tag 25
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26
|
||||
|
@ -199,14 +171,11 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
|||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_zip_file_tag 29
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_platform_info_tag 31
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_extensions_tag 32
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_swizzling_enabled_tag 33
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_error_count_tag 34
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_warning_count_tag 35
|
||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34];
|
||||
extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22];
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||
|
||||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||
FirebaseStorage.
|
||||
|
||||
The repository also includes GoogleUtilities source. The
|
||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||
|
@ -75,14 +76,30 @@ the following software:
|
|||
|
||||
* Xcode 10.1 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||
|
||||
For the pod that you want to develop:
|
||||
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
|
||||
Firestore and Functions have self contained Xcode projects. See
|
||||
[Firestore/README.md](Firestore/README.md) and
|
||||
[Functions/README.md](Functions/README.md).
|
||||
Note: If the CocoaPods cache is out of date, you may need to run
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
||||
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
|
||||
those platforms. Since 10.2, Xcode does not properly handle multi-platform
|
||||
CocoaPods workspaces.
|
||||
|
||||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* Sign the App in the Settings Signing & Capabilities tab
|
||||
* Click Pods in the Project Manager
|
||||
* Add Signing to the iOS host app and unit test targets
|
||||
* Select the Unit-unit scheme
|
||||
* Run it to build and test
|
||||
|
||||
### Adding a New Firebase Pod
|
||||
|
||||
|
@ -99,13 +116,17 @@ Travis will verify that any code changes are done in a style compliant way. Inst
|
|||
These commands will get the right versions:
|
||||
|
||||
```
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
|
||||
```
|
||||
|
||||
Note: if you already have a newer version of these installed you may need to
|
||||
`brew switch` to this version.
|
||||
|
||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
||||
match the versions in the CI failure logs
|
||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||
|
@ -178,32 +199,39 @@ We've seen an amazing amount of interest and contributions to improve the Fireba
|
|||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||
participate in the Firebase community.
|
||||
|
||||
### macOS and tvOS
|
||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||
macOS and tvOS.
|
||||
### tvOS, macOS, and Catalyst
|
||||
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||
FirebaseDatabase, FirebaseMessaging, FirebaseFirestore,
|
||||
FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on
|
||||
tvOS, macOS, and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
|
||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
Note that the Firebase pod is not available for macOS and tvOS.
|
||||
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
To install, add a subset of the following to the Podfile:
|
||||
|
||||
```
|
||||
pod 'FirebaseAuth'
|
||||
pod 'FirebaseCore'
|
||||
pod 'FirebaseDatabase'
|
||||
pod 'FirebaseFirestore'
|
||||
pod 'FirebaseFunctions'
|
||||
pod 'FirebaseMessaging'
|
||||
pod 'FirebaseStorage'
|
||||
pod 'Firebase/ABTesting'
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Functions'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
```
|
||||
|
||||
#### Additional Catalyst Notes
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
to Build Settings.
|
||||
* FirebaseFirestore requires signing the
|
||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||
|
|
|
@ -19,36 +19,34 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||
static NSString *const kFIRCDIsDataCollectionDefaultEnabledKey =
|
||||
@"FIRCDIsDataCollectionDefaultEnabledKey";
|
||||
#define kFIRCDIsDataCollectionDefaultEnabledKey @"FIRCDIsDataCollectionDefaultEnabledKey"
|
||||
|
||||
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||
static NSString *const kFIRCDConfigurationTypeKey = @"FIRCDConfigurationTypeKey";
|
||||
#define kFIRCDConfigurationTypeKey @"FIRCDConfigurationTypeKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDSdkNameKey = @"FIRCDSdkNameKey";
|
||||
#define kFIRCDSdkNameKey @"FIRCDSdkNameKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDSdkVersionKey = @"FIRCDSdkVersionKey";
|
||||
#define kFIRCDSdkVersionKey @"FIRCDSdkVersionKey"
|
||||
|
||||
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||
static NSString *const kFIRCDllAppsCountKey = @"FIRCDllAppsCountKey";
|
||||
#define kFIRCDllAppsCountKey @"FIRCDllAppsCountKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDGoogleAppIDKey = @"FIRCDGoogleAppIDKey";
|
||||
#define kFIRCDGoogleAppIDKey @"FIRCDGoogleAppIDKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDBundleIDKey = @"FIRCDBundleID";
|
||||
#define kFIRCDBundleIDKey @"FIRCDBundleID"
|
||||
|
||||
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||
static NSString *const kFIRCDUsingOptionsFromDefaultPlistKey =
|
||||
@"FIRCDUsingOptionsFromDefaultPlistKey";
|
||||
#define kFIRCDUsingOptionsFromDefaultPlistKey @"FIRCDUsingOptionsFromDefaultPlistKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDLibraryVersionIDKey = @"FIRCDLibraryVersionIDKey";
|
||||
#define kFIRCDLibraryVersionIDKey @"FIRCDLibraryVersionIDKey"
|
||||
|
||||
/** If present, is an NSString. */
|
||||
static NSString *const kFIRCDFirebaseUserAgentKey = @"FIRCDFirebaseUserAgentKey";
|
||||
#define kFIRCDFirebaseUserAgentKey @"FIRCDFirebaseUserAgentKey"
|
||||
|
||||
/** Defines the interface of a data object needed to log diagnostics data. */
|
||||
@protocol FIRCoreDiagnosticsData <NSObject>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||
|
||||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||
FirebaseStorage.
|
||||
|
||||
The repository also includes GoogleUtilities source. The
|
||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||
|
@ -75,14 +76,30 @@ the following software:
|
|||
|
||||
* Xcode 10.1 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||
|
||||
For the pod that you want to develop:
|
||||
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
|
||||
Firestore and Functions have self contained Xcode projects. See
|
||||
[Firestore/README.md](Firestore/README.md) and
|
||||
[Functions/README.md](Functions/README.md).
|
||||
Note: If the CocoaPods cache is out of date, you may need to run
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
||||
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
|
||||
those platforms. Since 10.2, Xcode does not properly handle multi-platform
|
||||
CocoaPods workspaces.
|
||||
|
||||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* Sign the App in the Settings Signing & Capabilities tab
|
||||
* Click Pods in the Project Manager
|
||||
* Add Signing to the iOS host app and unit test targets
|
||||
* Select the Unit-unit scheme
|
||||
* Run it to build and test
|
||||
|
||||
### Adding a New Firebase Pod
|
||||
|
||||
|
@ -99,13 +116,17 @@ Travis will verify that any code changes are done in a style compliant way. Inst
|
|||
These commands will get the right versions:
|
||||
|
||||
```
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
|
||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
|
||||
```
|
||||
|
||||
Note: if you already have a newer version of these installed you may need to
|
||||
`brew switch` to this version.
|
||||
|
||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
||||
match the versions in the CI failure logs
|
||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||
|
@ -178,32 +199,39 @@ We've seen an amazing amount of interest and contributions to improve the Fireba
|
|||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||
participate in the Firebase community.
|
||||
|
||||
### macOS and tvOS
|
||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||
macOS and tvOS.
|
||||
### tvOS, macOS, and Catalyst
|
||||
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||
FirebaseDatabase, FirebaseMessaging, FirebaseFirestore,
|
||||
FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on
|
||||
tvOS, macOS, and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
|
||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
Note that the Firebase pod is not available for macOS and tvOS.
|
||||
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
|
||||
To install, add a subset of the following to the Podfile:
|
||||
|
||||
```
|
||||
pod 'FirebaseAuth'
|
||||
pod 'FirebaseCore'
|
||||
pod 'FirebaseDatabase'
|
||||
pod 'FirebaseFirestore'
|
||||
pod 'FirebaseFunctions'
|
||||
pod 'FirebaseMessaging'
|
||||
pod 'FirebaseStorage'
|
||||
pod 'Firebase/ABTesting'
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Functions'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
```
|
||||
|
||||
#### Additional Catalyst Notes
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
to Build Settings.
|
||||
* FirebaseFirestore requires signing the
|
||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <FirebaseInstallations/FIRInstallationsErrors.h>
|
||||
|
||||
@class FIRInstallationsHTTPError;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer);
|
||||
|
||||
@interface FIRInstallationsErrorUtil : NSObject
|
||||
|
||||
+ (NSError *)keyedArchiverErrorWithException:(NSException *)exception;
|
||||
+ (NSError *)keyedArchiverErrorWithError:(NSError *)error;
|
||||
|
||||
+ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status;
|
||||
|
||||
+ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName;
|
||||
|
||||
+ (NSError *)JSONSerializationError:(NSError *)error;
|
||||
|
||||
+ (NSError *)networkErrorWithError:(NSError *)error;
|
||||
|
||||
+ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName;
|
||||
|
||||
+ (NSError *)corruptedIIDTokenData;
|
||||
|
||||
+ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse
|
||||
data:(nullable NSData *)data;
|
||||
+ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode;
|
||||
|
||||
/**
|
||||
* Returns the passed error if it is already in the public domain or a new error with the passed
|
||||
* error at `NSUnderlyingErrorKey`.
|
||||
*/
|
||||
+ (NSError *)publicDomainErrorWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
124
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m
generated
Normal file
124
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m
generated
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
|
||||
#import "FIRInstallationsHTTPError.h"
|
||||
|
||||
NSString *const kFirebaseInstallationsErrorDomain = @"com.firebase.installations";
|
||||
|
||||
void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer) {
|
||||
if (pointer != NULL) {
|
||||
*pointer = error;
|
||||
}
|
||||
}
|
||||
|
||||
@implementation FIRInstallationsErrorUtil
|
||||
|
||||
+ (NSError *)keyedArchiverErrorWithException:(NSException *)exception {
|
||||
NSString *failureReason = [NSString
|
||||
stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@",
|
||||
exception.name, exception.reason, exception.userInfo];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)keyedArchiverErrorWithError:(NSError *)error {
|
||||
NSString *failureReason = [NSString stringWithFormat:@"NSKeyedArchiver error."];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:error];
|
||||
}
|
||||
|
||||
+ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status {
|
||||
NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeKeychain
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName {
|
||||
NSString *failureReason =
|
||||
[NSString stringWithFormat:@"Installation for appID %@ appName %@ not found", appID, appName];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)corruptedIIDTokenData {
|
||||
NSString *failureReason =
|
||||
@"IID token data stored in Keychain is corrupted or in an incompatible format.";
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse
|
||||
data:(nullable NSData *)data {
|
||||
return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:HTTPResponse data:data];
|
||||
}
|
||||
|
||||
+ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode {
|
||||
if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [(FIRInstallationsHTTPError *)error HTTPResponse].statusCode == HTTPCode;
|
||||
}
|
||||
|
||||
+ (NSError *)JSONSerializationError:(NSError *)error {
|
||||
NSString *failureReason = [NSString stringWithFormat:@"Failed to serialize JSON data."];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName {
|
||||
NSString *failureReason = [NSString
|
||||
stringWithFormat:@"A required response field with name %@ is missing", missingFieldName];
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:failureReason
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)networkErrorWithError:(NSError *)error {
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable
|
||||
failureReason:@"Network connection error."
|
||||
underlyingError:error];
|
||||
}
|
||||
|
||||
+ (NSError *)publicDomainErrorWithError:(NSError *)error {
|
||||
if ([error.domain isEqualToString:kFirebaseInstallationsErrorDomain]) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown
|
||||
failureReason:nil
|
||||
underlyingError:error];
|
||||
}
|
||||
|
||||
+ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code
|
||||
failureReason:(nullable NSString *)failureReason
|
||||
underlyingError:(nullable NSError *)underlyingError {
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
userInfo[NSUnderlyingErrorKey] = underlyingError;
|
||||
userInfo[NSLocalizedFailureReasonErrorKey] = failureReason;
|
||||
|
||||
return [NSError errorWithDomain:kFirebaseInstallationsErrorDomain code:code userInfo:userInfo];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Represents an error caused by an unexpected API response. */
|
||||
@interface FIRInstallationsHTTPError : NSError
|
||||
|
||||
@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse;
|
||||
@property(nonatomic, readonly, nonnull) NSData *data;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse data:(nullable NSData *)data;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
typedef NS_ENUM(NSInteger, FIRInstallationsHTTPCodes) {
|
||||
FIRInstallationsHTTPCodesTooManyRequests = 429,
|
||||
FIRInstallationsHTTPCodesServerInternalError = 500,
|
||||
};
|
||||
|
||||
/** Possible response HTTP codes for `CreateInstallation` API request. */
|
||||
typedef NS_ENUM(NSInteger, FIRInstallationsRegistrationHTTPCode) {
|
||||
FIRInstallationsRegistrationHTTPCodeSuccess = 201,
|
||||
FIRInstallationsRegistrationHTTPCodeInvalidArgument = 400,
|
||||
FIRInstallationsRegistrationHTTPCodeInvalidAPIKey = 401,
|
||||
FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch = 403,
|
||||
FIRInstallationsRegistrationHTTPCodeProjectNotFound = 404,
|
||||
FIRInstallationsRegistrationHTTPCodeTooManyRequests = 429,
|
||||
FIRInstallationsRegistrationHTTPCodeServerInternalError = 500
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenHTTPCode) {
|
||||
FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication = 401,
|
||||
FIRInstallationsAuthTokenHTTPCodeFIDNotFound = 404,
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsHTTPError.h"
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
|
||||
@implementation FIRInstallationsHTTPError
|
||||
|
||||
- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse
|
||||
data:(nullable NSData *)data {
|
||||
NSDictionary *userInfo = [FIRInstallationsHTTPError userInfoWithHTTPResponse:HTTPResponse
|
||||
data:data];
|
||||
self = [super
|
||||
initWithDomain:kFirebaseInstallationsErrorDomain
|
||||
code:[FIRInstallationsHTTPError errorCodeWithHTTPCode:HTTPResponse.statusCode]
|
||||
userInfo:userInfo];
|
||||
if (self) {
|
||||
_HTTPResponse = HTTPResponse;
|
||||
_data = data;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (FIRInstallationsErrorCode)errorCodeWithHTTPCode:(NSInteger)HTTPCode {
|
||||
return FIRInstallationsErrorCodeUnknown;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)userInfoWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse
|
||||
data:(nullable NSData *)data {
|
||||
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSString *failureReason = [NSString
|
||||
stringWithFormat:@"The server responded with an error. HTTP response: %@\nResponse body: %@",
|
||||
HTTPResponse, responseString];
|
||||
return @{NSLocalizedFailureReasonErrorKey : failureReason};
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:self.HTTPResponse data:self.data];
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder {
|
||||
NSHTTPURLResponse *HTTPResponse = [coder decodeObjectOfClass:[NSHTTPURLResponse class]
|
||||
forKey:@"HTTPResponse"];
|
||||
if (!HTTPResponse) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [coder decodeObjectOfClass:[NSData class] forKey:@"data"];
|
||||
|
||||
return [self initWithHTTPResponse:HTTPResponse data:data];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.HTTPResponse forKey:@"HTTPResponse"];
|
||||
[coder encodeObject:self.data forKey:@"data"];
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
248
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m
generated
Normal file
248
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m
generated
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallations.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import <FirebaseCore/FIRAppInternal.h>
|
||||
#import <FirebaseCore/FIRComponent.h>
|
||||
#import <FirebaseCore/FIRComponentContainer.h>
|
||||
#import <FirebaseCore/FIRLibrary.h>
|
||||
#import <FirebaseCore/FIRLogger.h>
|
||||
#import <FirebaseCore/FIROptions.h>
|
||||
|
||||
#import "FIRInstallationsAuthTokenResultInternal.h"
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsIDController.h"
|
||||
#import "FIRInstallationsItem.h"
|
||||
#import "FIRInstallationsLogger.h"
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
#import "FIRInstallationsVersion.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FIRInstallationsInstanceProvider <FIRLibrary>
|
||||
@end
|
||||
|
||||
@interface FIRInstallations () <FIRInstallationsInstanceProvider>
|
||||
@property(nonatomic, readonly) FIROptions *appOptions;
|
||||
@property(nonatomic, readonly) NSString *appName;
|
||||
|
||||
@property(nonatomic, readonly) FIRInstallationsIDController *installationsIDController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRInstallations
|
||||
|
||||
#pragma mark - Firebase component
|
||||
|
||||
+ (void)load {
|
||||
[FIRApp registerInternalLibrary:(Class<FIRLibrary>)self
|
||||
withName:@"fire-install"
|
||||
withVersion:[NSString stringWithUTF8String:FIRInstallationsVersionStr]];
|
||||
}
|
||||
|
||||
+ (nonnull NSArray<FIRComponent *> *)componentsToRegister {
|
||||
FIRComponentCreationBlock creationBlock =
|
||||
^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
|
||||
*isCacheable = YES;
|
||||
FIRInstallations *installations = [[FIRInstallations alloc] initWithApp:container.app];
|
||||
return installations;
|
||||
};
|
||||
|
||||
FIRComponent *installationsProvider =
|
||||
[FIRComponent componentWithProtocol:@protocol(FIRInstallationsInstanceProvider)
|
||||
instantiationTiming:FIRInstantiationTimingAlwaysEager
|
||||
dependencies:@[]
|
||||
creationBlock:creationBlock];
|
||||
return @[ installationsProvider ];
|
||||
}
|
||||
|
||||
- (instancetype)initWithApp:(FIRApp *)app {
|
||||
return [self initWitAppOptions:app.options appName:app.name];
|
||||
}
|
||||
|
||||
- (instancetype)initWitAppOptions:(FIROptions *)appOptions appName:(NSString *)appName {
|
||||
FIRInstallationsIDController *IDController =
|
||||
[[FIRInstallationsIDController alloc] initWithGoogleAppID:appOptions.googleAppID
|
||||
appName:appName
|
||||
APIKey:appOptions.APIKey
|
||||
projectID:appOptions.projectID
|
||||
GCMSenderID:appOptions.GCMSenderID
|
||||
accessGroup:appOptions.appGroupID];
|
||||
return [self initWithAppOptions:appOptions
|
||||
appName:appName
|
||||
installationsIDController:IDController
|
||||
prefetchAuthToken:YES];
|
||||
}
|
||||
|
||||
/// The initializer is supposed to be used by tests to inject `installationsStore`.
|
||||
- (instancetype)initWithAppOptions:(FIROptions *)appOptions
|
||||
appName:(NSString *)appName
|
||||
installationsIDController:(FIRInstallationsIDController *)installationsIDController
|
||||
prefetchAuthToken:(BOOL)prefetchAuthToken {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[[self class] validateAppOptions:appOptions appName:appName];
|
||||
[[self class] assertCompatibleIIDVersion];
|
||||
|
||||
_appOptions = [appOptions copy];
|
||||
_appName = [appName copy];
|
||||
_installationsIDController = installationsIDController;
|
||||
|
||||
// Pre-fetch auth token.
|
||||
if (prefetchAuthToken) {
|
||||
[self authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
|
||||
NSError *_Nullable error){
|
||||
}];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)validateAppOptions:(FIROptions *)appOptions appName:(NSString *)appName {
|
||||
NSMutableArray *missingFields = [NSMutableArray array];
|
||||
if (appName.length < 1) {
|
||||
[missingFields addObject:@"`FirebaseApp.name`"];
|
||||
}
|
||||
if (appOptions.APIKey.length < 1) {
|
||||
[missingFields addObject:@"`FirebaseOptions.APIKey`"];
|
||||
}
|
||||
if (appOptions.googleAppID.length < 1) {
|
||||
[missingFields addObject:@"`FirebaseOptions.googleAppID`"];
|
||||
}
|
||||
|
||||
// TODO(#4692): Check for `appOptions.projectID.length < 1` only.
|
||||
// We can use `GCMSenderID` instead of `projectID` temporary.
|
||||
if (appOptions.projectID.length < 1 && appOptions.GCMSenderID.length < 1) {
|
||||
[missingFields addObject:@"`FirebaseOptions.projectID`"];
|
||||
}
|
||||
|
||||
if (missingFields.count > 0) {
|
||||
[NSException
|
||||
raise:kFirebaseInstallationsErrorDomain
|
||||
format:
|
||||
@"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp "
|
||||
@"options. The following parameters are nil or empty: %@. If you use "
|
||||
@"GoogleServices-Info.plist please download the most recent version from the Firebase "
|
||||
@"Console. If you configure Firebase in code, please make sure you specify all "
|
||||
@"required parameters.",
|
||||
kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions,
|
||||
[missingFields componentsJoinedByString:@", "]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
+ (FIRInstallations *)installations {
|
||||
FIRApp *defaultApp = [FIRApp defaultApp];
|
||||
if (!defaultApp) {
|
||||
[NSException raise:kFirebaseInstallationsErrorDomain
|
||||
format:@"The default FirebaseApp instance must be configured before the default"
|
||||
@"FirebaseApp instance can be initialized. One way to ensure that is to "
|
||||
@"call `[FIRApp configure];` (`FirebaseApp.configure()` in Swift) in the App"
|
||||
@" Delegate's `application:didFinishLaunchingWithOptions:` "
|
||||
@"(`application(_:didFinishLaunchingWithOptions:)` in Swift)."];
|
||||
}
|
||||
|
||||
return [self installationsWithApp:defaultApp];
|
||||
}
|
||||
|
||||
+ (FIRInstallations *)installationsWithApp:(FIRApp *)app {
|
||||
id<FIRInstallationsInstanceProvider> installations =
|
||||
FIR_COMPONENT(FIRInstallationsInstanceProvider, app.container);
|
||||
return (FIRInstallations *)installations;
|
||||
}
|
||||
|
||||
- (void)installationIDWithCompletion:(FIRInstallationsIDHandler)completion {
|
||||
[self.installationsIDController getInstallationItem]
|
||||
.then(^id(FIRInstallationsItem *installation) {
|
||||
completion(installation.firebaseInstallationID, nil);
|
||||
return nil;
|
||||
})
|
||||
.catch(^(NSError *error) {
|
||||
completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)authTokenWithCompletion:(FIRInstallationsTokenHandler)completion {
|
||||
[self authTokenForcingRefresh:NO completion:completion];
|
||||
}
|
||||
|
||||
- (void)authTokenForcingRefresh:(BOOL)forceRefresh
|
||||
completion:(FIRInstallationsTokenHandler)completion {
|
||||
[self.installationsIDController getAuthTokenForcingRefresh:forceRefresh]
|
||||
.then(^FIRInstallationsAuthTokenResult *(FIRInstallationsItem *installation) {
|
||||
FIRInstallationsAuthTokenResult *result = [[FIRInstallationsAuthTokenResult alloc]
|
||||
initWithToken:installation.authToken.token
|
||||
expirationDate:installation.authToken.expirationDate];
|
||||
return result;
|
||||
})
|
||||
.then(^id(FIRInstallationsAuthTokenResult *token) {
|
||||
completion(token, nil);
|
||||
return nil;
|
||||
})
|
||||
.catch(^void(NSError *error) {
|
||||
completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion {
|
||||
[self.installationsIDController deleteInstallation]
|
||||
.then(^id(id result) {
|
||||
completion(nil);
|
||||
return nil;
|
||||
})
|
||||
.catch(^void(NSError *error) {
|
||||
completion([FIRInstallationsErrorUtil publicDomainErrorWithError:error]);
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - IID version compatibility
|
||||
|
||||
+ (void)assertCompatibleIIDVersion {
|
||||
// We use this flag to disable IID compatibility exception for unit tests.
|
||||
#ifdef FIR_INSTALLATIONS_ALLOWS_INCOMPATIBLE_IID_VERSION
|
||||
return;
|
||||
#else
|
||||
if (![self isIIDVersionCompatible]) {
|
||||
[NSException raise:kFirebaseInstallationsErrorDomain
|
||||
format:@"FirebaseInstallations will not work correctly with current version of "
|
||||
@"Firebase Instance ID. Please update your Firebase Instance ID version."];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (BOOL)isIIDVersionCompatible {
|
||||
Class IIDClass = NSClassFromString(@"FIRInstanceID");
|
||||
if (IIDClass == nil) {
|
||||
// It is OK if there is no IID at all.
|
||||
return YES;
|
||||
}
|
||||
// We expect a compatible version having the method `+[FIRInstanceID usesFIS]` defined.
|
||||
BOOL isCompatibleVersion = [IIDClass respondsToSelector:NSSelectorFromString(@"usesFIS")];
|
||||
return isCompatibleVersion;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsAuthTokenResultInternal.h"
|
||||
|
||||
@implementation FIRInstallationsAuthTokenResult
|
||||
|
||||
- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationDate {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_authToken = [token copy];
|
||||
_expirationDate = expirationDate;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <FirebaseInstallations/FIRInstallationsAuthTokenResult.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FIRInstallationsAuthTokenResult (Internal)
|
||||
|
||||
- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationTime;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
86
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h
generated
Normal file
86
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h
generated
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FIRInstallationsStatus.h"
|
||||
|
||||
@class FIRInstallationsStoredItem;
|
||||
@class FIRInstallationsStoredAuthToken;
|
||||
@class FIRInstallationsStoredIIDCheckin;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The class represents the required installation ID and auth token data including possible states.
|
||||
* The data is stored to Keychain via `FIRInstallationsStoredItem` which has only the storage
|
||||
* relevant data and does not contain any logic. `FIRInstallationsItem` must be used on the logic
|
||||
* level (not `FIRInstallationsStoredItem`).
|
||||
*/
|
||||
@interface FIRInstallationsItem : NSObject <NSCopying>
|
||||
|
||||
/// A `FirebaseApp` identifier.
|
||||
@property(nonatomic, readonly) NSString *appID;
|
||||
/// A `FirebaseApp` name.
|
||||
@property(nonatomic, readonly) NSString *firebaseAppName;
|
||||
/// A stable identifier that uniquely identifies the app instance.
|
||||
@property(nonatomic, copy, nullable) NSString *firebaseInstallationID;
|
||||
/// The `refreshToken` is used to authorize the auth token requests.
|
||||
@property(nonatomic, copy, nullable) NSString *refreshToken;
|
||||
|
||||
@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken;
|
||||
@property(nonatomic, assign) FIRInstallationsStatus registrationStatus;
|
||||
|
||||
/// Instance ID default token imported from IID store as a part of IID migration.
|
||||
@property(nonatomic, nullable) NSString *IIDDefaultToken;
|
||||
|
||||
- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName;
|
||||
|
||||
/**
|
||||
* Populates `FIRInstallationsItem` properties with data from `FIRInstallationsStoredItem`.
|
||||
* @param item An instance of `FIRInstallationsStoredItem` to get data from.
|
||||
*/
|
||||
- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item;
|
||||
|
||||
/**
|
||||
* Creates a stored item with data from the object.
|
||||
* @return Returns a `FIRInstallationsStoredItem` instance with the data from the object.
|
||||
*/
|
||||
- (FIRInstallationsStoredItem *)storedItem;
|
||||
|
||||
/**
|
||||
* The installation identifier.
|
||||
* @return Returns a string uniquely identifying the installation.
|
||||
*/
|
||||
- (NSString *)identifier;
|
||||
|
||||
/**
|
||||
* The installation identifier.
|
||||
* @param appID A `FirebaseApp` identifier.
|
||||
* @param appName A `FirebaseApp` name.
|
||||
* @return Returns a string uniquely identifying the installation.
|
||||
*/
|
||||
+ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName;
|
||||
|
||||
/**
|
||||
* Generate a new Firebase Installation Identifier.
|
||||
* @return Returns a 22 characters long globally unique string created based on UUID.
|
||||
*/
|
||||
+ (NSString *)generateFID;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
104
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m
generated
Normal file
104
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m
generated
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsItem.h"
|
||||
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
#import "FIRInstallationsStoredItem.h"
|
||||
|
||||
@implementation FIRInstallationsItem
|
||||
|
||||
- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_appID = [appID copy];
|
||||
_firebaseAppName = [firebaseAppName copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
|
||||
FIRInstallationsItem *clone = [[FIRInstallationsItem alloc] initWithAppID:self.appID
|
||||
firebaseAppName:self.firebaseAppName];
|
||||
clone.firebaseInstallationID = [self.firebaseInstallationID copy];
|
||||
clone.refreshToken = [self.refreshToken copy];
|
||||
clone.authToken = [self.authToken copy];
|
||||
clone.registrationStatus = self.registrationStatus;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item {
|
||||
self.firebaseInstallationID = item.firebaseInstallationID;
|
||||
self.refreshToken = item.refreshToken;
|
||||
self.authToken = item.authToken;
|
||||
self.registrationStatus = item.registrationStatus;
|
||||
self.IIDDefaultToken = item.IIDDefaultToken;
|
||||
}
|
||||
|
||||
- (FIRInstallationsStoredItem *)storedItem {
|
||||
FIRInstallationsStoredItem *storedItem = [[FIRInstallationsStoredItem alloc] init];
|
||||
storedItem.firebaseInstallationID = self.firebaseInstallationID;
|
||||
storedItem.refreshToken = self.refreshToken;
|
||||
storedItem.authToken = self.authToken;
|
||||
storedItem.registrationStatus = self.registrationStatus;
|
||||
storedItem.IIDDefaultToken = self.IIDDefaultToken;
|
||||
return storedItem;
|
||||
}
|
||||
|
||||
- (nonnull NSString *)identifier {
|
||||
return [[self class] identifierWithAppID:self.appID appName:self.firebaseAppName];
|
||||
}
|
||||
|
||||
+ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName {
|
||||
return [appID stringByAppendingString:appName];
|
||||
}
|
||||
|
||||
+ (NSString *)generateFID {
|
||||
NSUUID *UUID = [NSUUID UUID];
|
||||
uuid_t UUIDBytes;
|
||||
[UUID getUUIDBytes:UUIDBytes];
|
||||
|
||||
NSUInteger UUIDLength = sizeof(uuid_t);
|
||||
NSData *UUIDData = [NSData dataWithBytes:UUIDBytes length:UUIDLength];
|
||||
|
||||
uint8_t UUIDLast4Bits = UUIDBytes[UUIDLength - 1] & 0b00001111;
|
||||
|
||||
// FID first 4 bits must be `0111`. The last 4 UUID bits will be cut later to form a proper FID.
|
||||
// To keep 16 random bytes we copy these last 4 UUID to the FID 1st byte after `0111` prefix.
|
||||
uint8_t FIDPrefix = 0b01110000 | UUIDLast4Bits;
|
||||
NSMutableData *FIDData = [NSMutableData dataWithBytes:&FIDPrefix length:1];
|
||||
|
||||
[FIDData appendData:UUIDData];
|
||||
NSString *FIDString = [self base64URLEncodedStringWithData:FIDData];
|
||||
|
||||
// A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 bytes.
|
||||
// Our generated ID has 16 bytes UUID + 1 byte prefix which after encoding with base64 will become
|
||||
// 23 characters plus 1 character for "=" padding.
|
||||
|
||||
// Remove the 23rd character that was added because of the extra 4 bits at the
|
||||
// end of our 17 byte data and the '=' padding.
|
||||
return [FIDString substringWithRange:NSMakeRange(0, 22)];
|
||||
}
|
||||
|
||||
+ (NSString *)base64URLEncodedStringWithData:(NSData *)data {
|
||||
NSString *string = [data base64EncodedStringWithOptions:0];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
|
||||
return string;
|
||||
}
|
||||
|
||||
@end
|
51
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h
generated
Normal file
51
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h
generated
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <FirebaseCore/FIRLogger.h>
|
||||
|
||||
extern FIRLoggerService kFIRLoggerInstallations;
|
||||
|
||||
// FIRInstallationsAPIService.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeSendAPIRequest;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIRequestResponse;
|
||||
extern NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse;
|
||||
extern NSString *const kFIRInstallationsMessageCodeParsingAPIResponse;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed;
|
||||
extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed;
|
||||
|
||||
// FIRInstallationsIDController.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated;
|
||||
extern NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated;
|
||||
extern NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated;
|
||||
extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration;
|
||||
|
||||
// FIRInstallationsStoredItem.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch;
|
||||
|
||||
// FIRInstallationsStoredAuthToken.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch;
|
||||
|
||||
// FIRInstallationsStoredIIDCheckin.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch;
|
||||
extern NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode;
|
||||
|
||||
// FIRInstallations.m
|
||||
extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions;
|
49
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m
generated
Normal file
49
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m
generated
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsLogger.h"
|
||||
|
||||
FIRLoggerService kFIRLoggerInstallations = @"[Firebase/Installations]";
|
||||
|
||||
// FIRInstallationsAPIService.m
|
||||
NSString *const kFIRInstallationsMessageCodeSendAPIRequest = @"I-FIS001001";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError = @"I-FIS001002";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIRequestResponse = @"I-FIS001003";
|
||||
NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse = @"I-FIS001004";
|
||||
NSString *const kFIRInstallationsMessageCodeParsingAPIResponse = @"I-FIS001005";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed = @"I-FIS001006";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed = @"I-FIS001007";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed = @"I-FIS001008";
|
||||
NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed = @"I-FIS001009";
|
||||
|
||||
// FIRInstallationsIDController.m
|
||||
NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated = @"I-FIS002000";
|
||||
NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated = @"I-FIS002001";
|
||||
NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated = @"I-FIS002002";
|
||||
NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration = @"I-FIS002003";
|
||||
|
||||
// FIRInstallationsStoredItem.m
|
||||
NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch = @"I-FIS003000";
|
||||
|
||||
// FIRInstallationsStoredAuthToken.m
|
||||
NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch = @"I-FIS004000";
|
||||
|
||||
// FIRInstallationsStoredIIDCheckin.m
|
||||
NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch = @"I-FIS007000";
|
||||
NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode = @"I-FIS007001";
|
||||
|
||||
// FIRInstallations.m
|
||||
NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions = @"I-FIS008000";
|
23
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsVersion.m
generated
Normal file
23
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsVersion.m
generated
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsVersion.h"
|
||||
|
||||
// Convert the macro to a string
|
||||
#define STR(x) STR_EXPAND(x)
|
||||
#define STR_EXPAND(x) #x
|
||||
|
||||
const char *const FIRInstallationsVersionStr = (const char *const)STR(FIRInstallations_LIB_VERSION);
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** The class encapsulates a port of a piece FirebaseInstanceID logic required to migrate IID. */
|
||||
@interface FIRInstallationsIIDStore : NSObject
|
||||
|
||||
/**
|
||||
* Retrieves existing IID if present.
|
||||
* @return Returns a promise that is resolved with IID string if IID has been found or rejected with
|
||||
* an error otherwise.
|
||||
*/
|
||||
- (FBLPromise<NSString *> *)existingIID;
|
||||
|
||||
/**
|
||||
* Deletes existing IID if present.
|
||||
* @return Returns a promise that is resolved with `[NSNull null]` if the IID was successfully.
|
||||
* deleted or was not found. The promise is rejected otherwise.
|
||||
*/
|
||||
- (FBLPromise<NSNull *> *)deleteExistingIID;
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
/// If not `nil`, then only this keychain will be used to save and read data (see
|
||||
/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests.
|
||||
@property(nonatomic, nullable) SecKeychainRef keychainRef;
|
||||
#endif // TARGET_OSX
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsIIDStore.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
|
||||
static NSString *const kFIRInstallationsIIDKeyPairPublicTagPrefix =
|
||||
@"com.google.iid.keypair.public-";
|
||||
static NSString *const kFIRInstallationsIIDKeyPairPrivateTagPrefix =
|
||||
@"com.google.iid.keypair.private-";
|
||||
static NSString *const kFIRInstallationsIIDCreationTimePlistKey = @"|S|cre";
|
||||
|
||||
@implementation FIRInstallationsIIDStore
|
||||
|
||||
- (FBLPromise<NSString *> *)existingIID {
|
||||
return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
|
||||
do:^id _Nullable {
|
||||
if (![self hasPlistIIDFlag]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *IIDPublicKeyData = [self IIDPublicKeyData];
|
||||
return [self IIDWithPublicKeyData:IIDPublicKeyData];
|
||||
}]
|
||||
.validate(^BOOL(NSString *_Nullable IID) {
|
||||
return IID.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)deleteExistingIID {
|
||||
return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
|
||||
do:^id _Nullable {
|
||||
NSError *error;
|
||||
if (![self deleteIIDFlagFromPlist:&error]) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (![self deleteIID:&error]) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return [NSNull null];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - IID decoding
|
||||
|
||||
- (NSString *)IIDWithPublicKeyData:(NSData *)publicKeyData {
|
||||
NSData *publicKeySHA1 = [self sha1WithData:publicKeyData];
|
||||
|
||||
const uint8_t *bytes = publicKeySHA1.bytes;
|
||||
NSMutableData *identityData = [NSMutableData dataWithData:publicKeySHA1];
|
||||
|
||||
uint8_t b0 = bytes[0];
|
||||
// Take the first byte and make the initial four 7 by initially making the initial 4 bits 0
|
||||
// and then adding 0x70 to it.
|
||||
b0 = 0x70 + (0xF & b0);
|
||||
// failsafe should give you back b0 itself
|
||||
b0 = (b0 & 0xFF);
|
||||
[identityData replaceBytesInRange:NSMakeRange(0, 1) withBytes:&b0];
|
||||
NSData *data = [identityData subdataWithRange:NSMakeRange(0, 8 * sizeof(Byte))];
|
||||
return [self base64URLEncodedStringWithData:data];
|
||||
}
|
||||
|
||||
- (NSData *)sha1WithData:(NSData *)data {
|
||||
unsigned char output[CC_SHA1_DIGEST_LENGTH];
|
||||
unsigned int length = (unsigned int)[data length];
|
||||
|
||||
CC_SHA1(data.bytes, length, output);
|
||||
return [NSData dataWithBytes:output length:CC_SHA1_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)base64URLEncodedStringWithData:(NSData *)data {
|
||||
NSString *string = [data base64EncodedStringWithOptions:0];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""];
|
||||
return string;
|
||||
}
|
||||
|
||||
#pragma mark - Keychain
|
||||
|
||||
- (NSData *)IIDPublicKeyData {
|
||||
NSString *tag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix];
|
||||
NSDictionary *query = [self keyPairQueryWithTag:tag returnData:YES];
|
||||
|
||||
CFTypeRef keyRef = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyRef);
|
||||
|
||||
if (status != noErr) {
|
||||
if (keyRef) {
|
||||
CFRelease(keyRef);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return (__bridge NSData *)keyRef;
|
||||
}
|
||||
|
||||
- (BOOL)deleteIID:(NSError **)outError {
|
||||
if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix
|
||||
error:outError]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPrivateTagPrefix
|
||||
error:outError]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)deleteKeychainKeyWithTagPrefix:(NSString *)tagPrefix error:(NSError **)outError {
|
||||
NSString *keyTag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix];
|
||||
NSDictionary *keyQuery = [self keyPairQueryWithTag:keyTag returnData:NO];
|
||||
|
||||
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)keyQuery);
|
||||
|
||||
// When item is not found, it should NOT be considered as an error. The operation should
|
||||
// continue.
|
||||
if (status != noErr && status != errSecItemNotFound) {
|
||||
FIRInstallationsItemSetErrorToPointer(
|
||||
[FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemDelete" status:status],
|
||||
outError);
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSDictionary *)keyPairQueryWithTag:(NSString *)tag returnData:(BOOL)shouldReturnData {
|
||||
NSMutableDictionary *query = [NSMutableDictionary dictionary];
|
||||
NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
query[(__bridge id)kSecClass] = (__bridge id)kSecClassKey;
|
||||
query[(__bridge id)kSecAttrApplicationTag] = tagData;
|
||||
query[(__bridge id)kSecAttrKeyType] = (__bridge id)kSecAttrKeyTypeRSA;
|
||||
if (shouldReturnData) {
|
||||
query[(__bridge id)kSecReturnData] = @(YES);
|
||||
}
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
if (self.keychainRef) {
|
||||
query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ];
|
||||
}
|
||||
#endif // TARGET_OSX
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
- (NSString *)keychainKeyTagWithPrefix:(NSString *)prefix {
|
||||
NSString *mainAppBundleID = [[NSBundle mainBundle] bundleIdentifier];
|
||||
if (mainAppBundleID.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@%@", prefix, mainAppBundleID];
|
||||
}
|
||||
|
||||
- (NSString *)mainbundleIdentifier {
|
||||
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
|
||||
if (!bundleIdentifier.length) {
|
||||
return nil;
|
||||
}
|
||||
return bundleIdentifier;
|
||||
}
|
||||
|
||||
#pragma mark - Plist
|
||||
|
||||
- (BOOL)deleteIIDFlagFromPlist:(NSError **)outError {
|
||||
NSString *path = [self plistPath];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSMutableDictionary *plistContent = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
|
||||
plistContent[kFIRInstallationsIIDCreationTimePlistKey] = nil;
|
||||
|
||||
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
|
||||
return [plistContent writeToURL:[NSURL fileURLWithPath:path] error:outError];
|
||||
}
|
||||
|
||||
return [plistContent writeToFile:path atomically:YES];
|
||||
}
|
||||
|
||||
- (BOOL)hasPlistIIDFlag {
|
||||
NSString *path = [self plistPath];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *plistContent = [[NSDictionary alloc] initWithContentsOfFile:path];
|
||||
return plistContent[kFIRInstallationsIIDCreationTimePlistKey] != nil;
|
||||
}
|
||||
|
||||
- (NSString *)plistPath {
|
||||
NSString *plistNameWithExtension = @"com.google.iid-keypair.plist";
|
||||
NSString *_subDirectoryName = @"Google/FirebaseInstanceID";
|
||||
|
||||
NSArray *directoryPaths =
|
||||
NSSearchPathForDirectoriesInDomains([self supportedDirectory], NSUserDomainMask, YES);
|
||||
NSArray *components = @[ directoryPaths.lastObject, _subDirectoryName, plistNameWithExtension ];
|
||||
|
||||
return [NSString pathWithComponents:components];
|
||||
}
|
||||
|
||||
- (NSSearchPathDirectory)supportedDirectory {
|
||||
#if TARGET_OS_TV
|
||||
return NSCachesDirectory;
|
||||
#else
|
||||
return NSApplicationSupportDirectory;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The class reads a default IID token from IID store if available.
|
||||
*/
|
||||
@interface FIRInstallationsIIDTokenStore : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID;
|
||||
|
||||
- (FBLPromise<NSString *> *)existingIIDDefaultToken;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsIIDTokenStore.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsKeychainUtils.h"
|
||||
|
||||
static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens";
|
||||
|
||||
@interface FIRInstallationsIIDTokenInfo : NSObject <NSSecureCoding>
|
||||
@property(nonatomic, nullable, copy) NSString *token;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsIIDTokenInfo
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FIRInstallationsIIDTokenStore ()
|
||||
@property(nonatomic, readonly) NSString *GCMSenderID;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsIIDTokenStore
|
||||
|
||||
- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_GCMSenderID = GCMSenderID;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (FBLPromise<NSString *> *)existingIIDDefaultToken {
|
||||
return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
|
||||
do:^id _Nullable {
|
||||
return [self IIDDefaultTokenData];
|
||||
}] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
|
||||
then:^id _Nullable(NSData *_Nullable keychainData) {
|
||||
return [self IIDCheckinWithData:keychainData];
|
||||
}];
|
||||
}
|
||||
|
||||
- (FBLPromise<NSString *> *)IIDCheckinWithData:(NSData *)data {
|
||||
FBLPromise<NSString *> *resultPromise = [FBLPromise pendingPromise];
|
||||
|
||||
NSError *archiverError;
|
||||
NSKeyedUnarchiver *unarchiver;
|
||||
if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) {
|
||||
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError];
|
||||
} else {
|
||||
@try {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
#pragma clang diagnostic pop
|
||||
} @catch (NSException *exception) {
|
||||
archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception];
|
||||
}
|
||||
}
|
||||
|
||||
if (!unarchiver) {
|
||||
NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
|
||||
[resultPromise reject:error];
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
[unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"];
|
||||
FIRInstallationsIIDTokenInfo *IIDTokenInfo =
|
||||
[unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class]
|
||||
forKey:NSKeyedArchiveRootObjectKey];
|
||||
|
||||
if (IIDTokenInfo.token.length < 1) {
|
||||
[resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]];
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
[resultPromise fulfill:IIDTokenInfo.token];
|
||||
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
- (FBLPromise<NSData *> *)IIDDefaultTokenData {
|
||||
FBLPromise<NSData *> *resultPromise = [FBLPromise pendingPromise];
|
||||
|
||||
NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery];
|
||||
NSError *error;
|
||||
NSData *data = [FIRInstallationsKeychainUtils getItemWithQuery:keychainQuery error:&error];
|
||||
|
||||
if (data) {
|
||||
[resultPromise fulfill:data];
|
||||
return resultPromise;
|
||||
} else {
|
||||
NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
|
||||
[resultPromise reject:outError];
|
||||
return resultPromise;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery {
|
||||
NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword};
|
||||
|
||||
NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query];
|
||||
finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId;
|
||||
|
||||
NSString *account = [self IIDAppIdentifier];
|
||||
if ([account length]) {
|
||||
finalQuery[(__bridge NSString *)kSecAttrAccount] = account;
|
||||
}
|
||||
|
||||
finalQuery[(__bridge NSString *)kSecAttrService] =
|
||||
[self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"];
|
||||
return finalQuery;
|
||||
}
|
||||
|
||||
- (NSString *)IIDAppIdentifier {
|
||||
return [[NSBundle mainBundle] bundleIdentifier] ?: @"";
|
||||
}
|
||||
|
||||
- (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {
|
||||
return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
@class FIRInstallationsItem;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
FOUNDATION_EXPORT NSString *const kFIRInstallationsUserAgentKey;
|
||||
|
||||
FOUNDATION_EXPORT NSString *const kFIRInstallationsHeartbeatKey;
|
||||
|
||||
/**
|
||||
* The class is responsible for interacting with HTTP REST API for Installations.
|
||||
*/
|
||||
@interface FIRInstallationsAPIService : NSObject
|
||||
|
||||
/**
|
||||
* The default initializer.
|
||||
* @param APIKey The Firebase project API key (see `FIROptions.APIKey`).
|
||||
* @param projectID The Firebase project ID (see `FIROptions.projectID`).
|
||||
*/
|
||||
- (instancetype)initWithAPIKey:(NSString *)APIKey projectID:(NSString *)projectID;
|
||||
|
||||
/**
|
||||
* Sends a request to register a new FID to get auth and refresh tokens.
|
||||
* @param installation The `FIRInstallationsItem` instance with the FID to register.
|
||||
* @return A promise that is resolved with a new `FIRInstallationsItem` instance with valid tokens.
|
||||
* It is rejected with an error in case of a failure.
|
||||
*/
|
||||
- (FBLPromise<FIRInstallationsItem *> *)registerInstallation:(FIRInstallationsItem *)installation;
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)refreshAuthTokenForInstallation:
|
||||
(FIRInstallationsItem *)installation;
|
||||
|
||||
/**
|
||||
* Sends a request to delete the installation, related auth tokens and all related data from the
|
||||
* server.
|
||||
* @param installation The installation to delete.
|
||||
* @return Returns a promise that is resolved with the passed installation on successful deletion or
|
||||
* is rejected with an error otherwise.
|
||||
*/
|
||||
- (FBLPromise<FIRInstallationsItem *> *)deleteInstallation:(FIRInstallationsItem *)installation;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsAPIService.h"
|
||||
|
||||
#import <FirebaseInstallations/FIRInstallationsVersion.h>
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import <FirebaseCore/FIRAppInternal.h>
|
||||
#import <FirebaseCore/FIRHeartbeatInfo.h>
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsItem+RegisterInstallationAPI.h"
|
||||
#import "FIRInstallationsLogger.h"
|
||||
|
||||
NSString *const kFIRInstallationsAPIBaseURL = @"https://firebaseinstallations.googleapis.com";
|
||||
NSString *const kFIRInstallationsAPIKey = @"X-Goog-Api-Key";
|
||||
NSString *const kFIRInstallationsBundleId = @"X-Ios-Bundle-Identifier";
|
||||
NSString *const kFIRInstallationsIIDMigrationAuthHeader = @"x-goog-fis-ios-iid-migration-auth";
|
||||
NSString *const kFIRInstallationsHeartbeatKey = @"X-firebase-client-log-type";
|
||||
NSString *const kFIRInstallationsHeartbeatTag = @"fire-installations";
|
||||
NSString *const kFIRInstallationsUserAgentKey = @"X-firebase-client";
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FIRInstallationsURLSessionResponse : NSObject
|
||||
@property(nonatomic) NSHTTPURLResponse *HTTPResponse;
|
||||
@property(nonatomic) NSData *data;
|
||||
|
||||
- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsURLSessionResponse
|
||||
|
||||
- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_HTTPResponse = response;
|
||||
_data = data ?: [NSData data];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FIRInstallationsAPIService ()
|
||||
@property(nonatomic, readonly) NSURLSession *URLSession;
|
||||
@property(nonatomic, readonly) NSString *APIKey;
|
||||
@property(nonatomic, readonly) NSString *projectID;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@implementation FIRInstallationsAPIService
|
||||
|
||||
- (instancetype)initWithAPIKey:(NSString *)APIKey projectID:(NSString *)projectID {
|
||||
NSURLSession *URLSession = [NSURLSession
|
||||
sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
|
||||
return [self initWithURLSession:URLSession APIKey:APIKey projectID:projectID];
|
||||
}
|
||||
|
||||
/// The initializer for tests.
|
||||
- (instancetype)initWithURLSession:(NSURLSession *)URLSession
|
||||
APIKey:(NSString *)APIKey
|
||||
projectID:(NSString *)projectID {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_URLSession = URLSession;
|
||||
_APIKey = [APIKey copy];
|
||||
_projectID = [projectID copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)registerInstallation:(FIRInstallationsItem *)installation {
|
||||
NSURLRequest *request = [self registerRequestWithInstallation:installation];
|
||||
return [self sendURLRequest:request].then(
|
||||
^id _Nullable(FIRInstallationsURLSessionResponse *response) {
|
||||
return [self registeredInstallationWithInstallation:installation serverResponse:response];
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)refreshAuthTokenForInstallation:
|
||||
(FIRInstallationsItem *)installation {
|
||||
NSURLRequest *request = [self authTokenRequestWithInstallation:installation];
|
||||
return [self sendURLRequest:request]
|
||||
.then(^FBLPromise<FIRInstallationsStoredAuthToken *> *(
|
||||
FIRInstallationsURLSessionResponse *response) {
|
||||
return [self authTokenWithServerResponse:response];
|
||||
})
|
||||
.then(^FIRInstallationsItem *(FIRInstallationsStoredAuthToken *authToken) {
|
||||
FIRInstallationsItem *updatedInstallation = [installation copy];
|
||||
updatedInstallation.authToken = authToken;
|
||||
return updatedInstallation;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)deleteInstallation:(FIRInstallationsItem *)installation {
|
||||
NSURLRequest *request = [self deleteInstallationRequestWithInstallation:installation];
|
||||
return [[self sendURLRequest:request]
|
||||
then:^id _Nullable(FIRInstallationsURLSessionResponse *_Nullable value) {
|
||||
// Return the original installation on success.
|
||||
return installation;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Register Installation
|
||||
|
||||
- (NSURLRequest *)registerRequestWithInstallation:(FIRInstallationsItem *)installation {
|
||||
NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/",
|
||||
kFIRInstallationsAPIBaseURL, self.projectID];
|
||||
NSURL *URL = [NSURL URLWithString:URLString];
|
||||
|
||||
NSDictionary *bodyDict = @{
|
||||
@"fid" : installation.firebaseInstallationID,
|
||||
@"authVersion" : @"FIS_v2",
|
||||
@"appId" : installation.appID,
|
||||
@"sdkVersion" : [self SDKVersion]
|
||||
};
|
||||
|
||||
NSDictionary *headers;
|
||||
if (installation.IIDDefaultToken) {
|
||||
headers = @{kFIRInstallationsIIDMigrationAuthHeader : installation.IIDDefaultToken};
|
||||
}
|
||||
|
||||
return [self requestWithURL:URL
|
||||
HTTPMethod:@"POST"
|
||||
bodyDict:bodyDict
|
||||
refreshToken:nil
|
||||
additionalHeaders:headers];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)
|
||||
registeredInstallationWithInstallation:(FIRInstallationsItem *)installation
|
||||
serverResponse:(FIRInstallationsURLSessionResponse *)response {
|
||||
return [FBLPromise do:^id {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse,
|
||||
@"Parsing server response for %@.", response.HTTPResponse.URL);
|
||||
NSError *error;
|
||||
FIRInstallationsItem *registeredInstallation =
|
||||
[installation registeredInstallationWithJSONData:response.data
|
||||
date:[NSDate date]
|
||||
error:&error];
|
||||
if (registeredInstallation == nil) {
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed,
|
||||
@"Failed to parse FIRInstallationsItem: %@.", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed,
|
||||
@"FIRInstallationsItem parsed successfully.");
|
||||
return registeredInstallation;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Auth token
|
||||
|
||||
- (NSURLRequest *)authTokenRequestWithInstallation:(FIRInstallationsItem *)installation {
|
||||
NSString *URLString =
|
||||
[NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/authTokens:generate",
|
||||
kFIRInstallationsAPIBaseURL, self.projectID,
|
||||
installation.firebaseInstallationID];
|
||||
NSURL *URL = [NSURL URLWithString:URLString];
|
||||
|
||||
NSDictionary *bodyDict = @{@"installation" : @{@"sdkVersion" : [self SDKVersion]}};
|
||||
return [self requestWithURL:URL
|
||||
HTTPMethod:@"POST"
|
||||
bodyDict:bodyDict
|
||||
refreshToken:installation.refreshToken];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsStoredAuthToken *> *)authTokenWithServerResponse:
|
||||
(FIRInstallationsURLSessionResponse *)response {
|
||||
return [FBLPromise do:^id {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse,
|
||||
@"Parsing server response for %@.", response.HTTPResponse.URL);
|
||||
NSError *error;
|
||||
FIRInstallationsStoredAuthToken *token =
|
||||
[FIRInstallationsItem authTokenWithGenerateTokenAPIJSONData:response.data
|
||||
date:[NSDate date]
|
||||
error:&error];
|
||||
if (token == nil) {
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed,
|
||||
@"Failed to parse FIRInstallationsStoredAuthToken: %@.", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed,
|
||||
@"FIRInstallationsStoredAuthToken parsed successfully.");
|
||||
return token;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Delete Installation
|
||||
|
||||
- (NSURLRequest *)deleteInstallationRequestWithInstallation:(FIRInstallationsItem *)installation {
|
||||
NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/",
|
||||
kFIRInstallationsAPIBaseURL, self.projectID,
|
||||
installation.firebaseInstallationID];
|
||||
NSURL *URL = [NSURL URLWithString:URLString];
|
||||
|
||||
return [self requestWithURL:URL
|
||||
HTTPMethod:@"DELETE"
|
||||
bodyDict:@{}
|
||||
refreshToken:installation.refreshToken];
|
||||
}
|
||||
|
||||
#pragma mark - URL Request
|
||||
- (NSURLRequest *)requestWithURL:(NSURL *)requestURL
|
||||
HTTPMethod:(NSString *)HTTPMethod
|
||||
bodyDict:(NSDictionary *)bodyDict
|
||||
refreshToken:(nullable NSString *)refreshToken {
|
||||
return [self requestWithURL:requestURL
|
||||
HTTPMethod:HTTPMethod
|
||||
bodyDict:bodyDict
|
||||
refreshToken:refreshToken
|
||||
additionalHeaders:nil];
|
||||
}
|
||||
|
||||
- (NSURLRequest *)requestWithURL:(NSURL *)requestURL
|
||||
HTTPMethod:(NSString *)HTTPMethod
|
||||
bodyDict:(NSDictionary *)bodyDict
|
||||
refreshToken:(nullable NSString *)refreshToken
|
||||
additionalHeaders:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalHeaders {
|
||||
__block NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL];
|
||||
request.HTTPMethod = HTTPMethod;
|
||||
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
|
||||
[request addValue:self.APIKey forHTTPHeaderField:kFIRInstallationsAPIKey];
|
||||
[request addValue:bundleIdentifier forHTTPHeaderField:kFIRInstallationsBundleId];
|
||||
[self setJSONHTTPBody:bodyDict forRequest:request];
|
||||
if (refreshToken) {
|
||||
NSString *authHeader = [NSString stringWithFormat:@"FIS_v2 %@", refreshToken];
|
||||
[request setValue:authHeader forHTTPHeaderField:@"Authorization"];
|
||||
}
|
||||
// User agent Header.
|
||||
[request setValue:[FIRApp firebaseUserAgent] forHTTPHeaderField:kFIRInstallationsUserAgentKey];
|
||||
// Heartbeat Header.
|
||||
[request setValue:@([FIRHeartbeatInfo heartbeatCodeForTag:kFIRInstallationsHeartbeatTag])
|
||||
.stringValue
|
||||
forHTTPHeaderField:kFIRInstallationsHeartbeatKey];
|
||||
[additionalHeaders enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSString *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
|
||||
[request setValue:obj forHTTPHeaderField:key];
|
||||
}];
|
||||
|
||||
return [request copy];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsURLSessionResponse *> *)URLRequestPromise:(NSURLRequest *)request {
|
||||
return [[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeSendAPIRequest,
|
||||
@"Sending request: %@, body:%@, headers: %@.", request,
|
||||
[[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding],
|
||||
request.allHTTPHeaderFields);
|
||||
[[self.URLSession
|
||||
dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response,
|
||||
NSError *_Nullable error) {
|
||||
if (error) {
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAPIRequestNetworkError,
|
||||
@"Request failed: %@, error: %@.", request, error);
|
||||
reject(error);
|
||||
} else {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeAPIRequestResponse,
|
||||
@"Request response received: %@, error: %@, body: %@.", request, error,
|
||||
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
||||
fulfill([[FIRInstallationsURLSessionResponse alloc]
|
||||
initWithResponse:(NSHTTPURLResponse *)response
|
||||
data:data]);
|
||||
}
|
||||
}] resume];
|
||||
}] then:^id _Nullable(FIRInstallationsURLSessionResponse *response) {
|
||||
return [self validateHTTPResponseStatusCode:response];
|
||||
}];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsURLSessionResponse *> *)validateHTTPResponseStatusCode:
|
||||
(FIRInstallationsURLSessionResponse *)response {
|
||||
NSInteger statusCode = response.HTTPResponse.statusCode;
|
||||
return [FBLPromise do:^id _Nullable {
|
||||
if (statusCode < 200 || statusCode >= 300) {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse,
|
||||
@"Unexpected API response: %@, body: %@.", response.HTTPResponse,
|
||||
[[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]);
|
||||
return [FIRInstallationsErrorUtil APIErrorWithHTTPResponse:response.HTTPResponse
|
||||
data:response.data];
|
||||
}
|
||||
return response;
|
||||
}];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsURLSessionResponse *> *)sendURLRequest:(NSURLRequest *)request {
|
||||
return [FBLPromise attempts:1
|
||||
delay:1
|
||||
condition:^BOOL(NSInteger remainingAttempts, NSError *_Nonnull error) {
|
||||
return [FIRInstallationsErrorUtil isAPIError:error withHTTPCode:500];
|
||||
}
|
||||
retry:^id _Nullable {
|
||||
return [self URLRequestPromise:request];
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)SDKVersion {
|
||||
return [NSString stringWithFormat:@"i:%s", FIRInstallationsVersionStr];
|
||||
}
|
||||
|
||||
#pragma mark - JSON
|
||||
|
||||
- (void)setJSONHTTPBody:(NSDictionary<NSString *, id> *)body
|
||||
forRequest:(NSMutableURLRequest *)request {
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSError *error;
|
||||
NSData *JSONData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error];
|
||||
if (JSONData == nil) {
|
||||
// TODO: Log or return an error.
|
||||
}
|
||||
request.HTTPBody = JSONData;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsItem.h"
|
||||
|
||||
@class FIRInstallationsStoredAuthToken;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FIRInstallationsItem (RegisterInstallationAPI)
|
||||
|
||||
/**
|
||||
* Parses and validates the Register Installation API response and returns a corresponding
|
||||
* `FIRInstallationsItem` instance on success.
|
||||
* @param JSONData The data with JSON encoded API response.
|
||||
* @param date The Auth Token expiration date will be calculated as `date` +
|
||||
* `response.authToken.expiresIn`. For most of the cases `[NSDate date]` should be passed there. A
|
||||
* different value may be passed e.g. for unit tests.
|
||||
* @param outError A pointer to assign a specific `NSError` instance in case of failure. No error is
|
||||
* assigned in case of success.
|
||||
* @return Returns a new `FIRInstallationsItem` instance in the success case or `nil` otherwise.
|
||||
*/
|
||||
- (nullable FIRInstallationsItem *)registeredInstallationWithJSONData:(NSData *)JSONData
|
||||
date:(NSDate *)date
|
||||
error:
|
||||
(NSError *_Nullable *)outError;
|
||||
|
||||
+ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data
|
||||
date:(NSDate *)date
|
||||
error:(NSError **)
|
||||
outError;
|
||||
|
||||
+ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict:
|
||||
(NSDictionary<NSString *, id> *)dict
|
||||
date:(NSDate *)date
|
||||
error:(NSError **)outError;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsItem+RegisterInstallationAPI.h"
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
|
||||
@implementation FIRInstallationsItem (RegisterInstallationAPI)
|
||||
|
||||
- (nullable FIRInstallationsItem *)
|
||||
registeredInstallationWithJSONData:(NSData *)data
|
||||
date:(NSDate *)date
|
||||
error:(NSError *__autoreleasing _Nullable *_Nullable)outError {
|
||||
NSDictionary *responseJSON = [FIRInstallationsItem dictionaryFromJSONData:data error:outError];
|
||||
if (!responseJSON) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *refreshToken = [FIRInstallationsItem validStringOrNilForKey:@"refreshToken"
|
||||
fromDict:responseJSON];
|
||||
if (refreshToken == nil) {
|
||||
FIRInstallationsItemSetErrorToPointer(
|
||||
[FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"refreshToken"],
|
||||
outError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *authTokenDict = responseJSON[@"authToken"];
|
||||
if (![authTokenDict isKindOfClass:[NSDictionary class]]) {
|
||||
FIRInstallationsItemSetErrorToPointer(
|
||||
[FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken"],
|
||||
outError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
FIRInstallationsStoredAuthToken *authToken =
|
||||
[FIRInstallationsItem authTokenWithJSONDict:authTokenDict date:date error:outError];
|
||||
if (authToken == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
FIRInstallationsItem *installation =
|
||||
[[FIRInstallationsItem alloc] initWithAppID:self.appID firebaseAppName:self.firebaseAppName];
|
||||
NSString *installationID = [FIRInstallationsItem validStringOrNilForKey:@"fid"
|
||||
fromDict:responseJSON];
|
||||
installation.firebaseInstallationID = installationID ?: self.firebaseInstallationID;
|
||||
installation.refreshToken = refreshToken;
|
||||
installation.authToken = authToken;
|
||||
installation.registrationStatus = FIRInstallationStatusRegistered;
|
||||
|
||||
return installation;
|
||||
}
|
||||
|
||||
#pragma mark - Auth token
|
||||
|
||||
+ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data
|
||||
date:(NSDate *)date
|
||||
error:(NSError **)
|
||||
outError {
|
||||
NSDictionary *dict = [self dictionaryFromJSONData:data error:outError];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self authTokenWithJSONDict:dict date:date error:outError];
|
||||
}
|
||||
|
||||
+ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict:
|
||||
(NSDictionary<NSString *, id> *)dict
|
||||
date:(NSDate *)date
|
||||
error:(NSError **)outError {
|
||||
NSString *token = [self validStringOrNilForKey:@"token" fromDict:dict];
|
||||
if (token == nil) {
|
||||
FIRInstallationsItemSetErrorToPointer(
|
||||
[FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken.token"],
|
||||
outError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *expiresInString = [self validStringOrNilForKey:@"expiresIn" fromDict:dict];
|
||||
if (expiresInString == nil) {
|
||||
FIRInstallationsItemSetErrorToPointer(
|
||||
[FIRInstallationsErrorUtil
|
||||
FIDRegistrationErrorWithResponseMissingField:@"authToken.expiresIn"],
|
||||
outError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// The response should contain the string in format like "604800s".
|
||||
// The server should never response with anything else except seconds.
|
||||
// Just drop the last character and parse a number from string.
|
||||
NSString *expiresInSeconds = [expiresInString substringToIndex:expiresInString.length - 1];
|
||||
NSTimeInterval expiresIn = [expiresInSeconds doubleValue];
|
||||
NSDate *expirationDate = [date dateByAddingTimeInterval:expiresIn];
|
||||
|
||||
FIRInstallationsStoredAuthToken *authToken = [[FIRInstallationsStoredAuthToken alloc] init];
|
||||
authToken.status = FIRInstallationsAuthTokenStatusTokenReceived;
|
||||
authToken.token = token;
|
||||
authToken.expirationDate = expirationDate;
|
||||
|
||||
return authToken;
|
||||
}
|
||||
|
||||
#pragma mark - JSON
|
||||
|
||||
+ (nullable NSDictionary<NSString *, id> *)dictionaryFromJSONData:(NSData *)data
|
||||
error:(NSError **)outError {
|
||||
NSError *error;
|
||||
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
|
||||
|
||||
if (![responseJSON isKindOfClass:[NSDictionary class]]) {
|
||||
FIRInstallationsItemSetErrorToPointer([FIRInstallationsErrorUtil JSONSerializationError:error],
|
||||
outError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return responseJSON;
|
||||
}
|
||||
|
||||
+ (NSString *)validStringOrNilForKey:(NSString *)key fromDict:(NSDictionary *)dict {
|
||||
NSString *string = dict[key];
|
||||
if ([string isKindOfClass:[NSString class]] && string.length > 0) {
|
||||
return string;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
@class FIRInstallationsItem;
|
||||
|
||||
/**
|
||||
* The class is responsible for managing FID for a given `FIRApp`.
|
||||
*/
|
||||
@interface FIRInstallationsIDController : NSObject
|
||||
|
||||
- (instancetype)initWithGoogleAppID:(NSString *)appID
|
||||
appName:(NSString *)appName
|
||||
APIKey:(NSString *)APIKey
|
||||
projectID:(NSString *)projectID
|
||||
GCMSenderID:(NSString *)GCMSenderID
|
||||
accessGroup:(nullable NSString *)accessGroup;
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)getInstallationItem;
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)getAuthTokenForcingRefresh:(BOOL)forceRefresh;
|
||||
|
||||
- (FBLPromise<NSNull *> *)deleteInstallation;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsIDController.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import <FirebaseCore/FIRAppInternal.h>
|
||||
|
||||
#import "FIRInstallationsAPIService.h"
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsIIDStore.h"
|
||||
#import "FIRInstallationsIIDTokenStore.h"
|
||||
#import "FIRInstallationsItem.h"
|
||||
#import "FIRInstallationsLogger.h"
|
||||
#import "FIRInstallationsSingleOperationPromiseCache.h"
|
||||
#import "FIRInstallationsStore.h"
|
||||
#import "FIRSecureStorage.h"
|
||||
|
||||
#import "FIRInstallationsHTTPError.h"
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
|
||||
const NSNotificationName FIRInstallationIDDidChangeNotification =
|
||||
@"FIRInstallationIDDidChangeNotification";
|
||||
NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey =
|
||||
@"FIRInstallationIDDidChangeNotification";
|
||||
|
||||
NSTimeInterval const kFIRInstallationsTokenExpirationThreshold = 60 * 60; // 1 hour.
|
||||
|
||||
@interface FIRInstallationsIDController ()
|
||||
@property(nonatomic, readonly) NSString *appID;
|
||||
@property(nonatomic, readonly) NSString *appName;
|
||||
|
||||
@property(nonatomic, readonly) FIRInstallationsStore *installationsStore;
|
||||
@property(nonatomic, readonly) FIRInstallationsIIDStore *IIDStore;
|
||||
@property(nonatomic, readonly) FIRInstallationsIIDTokenStore *IIDTokenStore;
|
||||
|
||||
@property(nonatomic, readonly) FIRInstallationsAPIService *APIService;
|
||||
|
||||
@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache<FIRInstallationsItem *>
|
||||
*getInstallationPromiseCache;
|
||||
@property(nonatomic, readonly)
|
||||
FIRInstallationsSingleOperationPromiseCache<FIRInstallationsItem *> *authTokenPromiseCache;
|
||||
@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache<FIRInstallationsItem *>
|
||||
*authTokenForcingRefreshPromiseCache;
|
||||
@property(nonatomic, readonly)
|
||||
FIRInstallationsSingleOperationPromiseCache<NSNull *> *deleteInstallationPromiseCache;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsIDController
|
||||
|
||||
- (instancetype)initWithGoogleAppID:(NSString *)appID
|
||||
appName:(NSString *)appName
|
||||
APIKey:(NSString *)APIKey
|
||||
projectID:(NSString *)projectID
|
||||
GCMSenderID:(NSString *)GCMSenderID
|
||||
accessGroup:(NSString *)accessGroup {
|
||||
FIRSecureStorage *secureStorage = [[FIRSecureStorage alloc] init];
|
||||
FIRInstallationsStore *installationsStore =
|
||||
[[FIRInstallationsStore alloc] initWithSecureStorage:secureStorage accessGroup:accessGroup];
|
||||
|
||||
// Use `GCMSenderID` as project identifier when `projectID` is not available.
|
||||
NSString *APIServiceProjectID = (projectID.length > 0) ? projectID : GCMSenderID;
|
||||
FIRInstallationsAPIService *apiService =
|
||||
[[FIRInstallationsAPIService alloc] initWithAPIKey:APIKey projectID:APIServiceProjectID];
|
||||
|
||||
FIRInstallationsIIDStore *IIDStore = [[FIRInstallationsIIDStore alloc] init];
|
||||
FIRInstallationsIIDTokenStore *IIDCheckingStore =
|
||||
[[FIRInstallationsIIDTokenStore alloc] initWithGCMSenderID:GCMSenderID];
|
||||
|
||||
return [self initWithGoogleAppID:appID
|
||||
appName:appName
|
||||
installationsStore:installationsStore
|
||||
APIService:apiService
|
||||
IIDStore:IIDStore
|
||||
IIDTokenStore:IIDCheckingStore];
|
||||
}
|
||||
|
||||
/// The initializer is supposed to be used by tests to inject `installationsStore`.
|
||||
- (instancetype)initWithGoogleAppID:(NSString *)appID
|
||||
appName:(NSString *)appName
|
||||
installationsStore:(FIRInstallationsStore *)installationsStore
|
||||
APIService:(FIRInstallationsAPIService *)APIService
|
||||
IIDStore:(FIRInstallationsIIDStore *)IIDStore
|
||||
IIDTokenStore:(FIRInstallationsIIDTokenStore *)IIDTokenStore {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_appID = appID;
|
||||
_appName = appName;
|
||||
_installationsStore = installationsStore;
|
||||
_APIService = APIService;
|
||||
_IIDStore = IIDStore;
|
||||
_IIDTokenStore = IIDTokenStore;
|
||||
|
||||
__weak FIRInstallationsIDController *weakSelf = self;
|
||||
|
||||
_getInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc]
|
||||
initWithNewOperationHandler:^FBLPromise *_Nonnull {
|
||||
FIRInstallationsIDController *strongSelf = weakSelf;
|
||||
return [strongSelf createGetInstallationItemPromise];
|
||||
}];
|
||||
|
||||
_authTokenPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc]
|
||||
initWithNewOperationHandler:^FBLPromise *_Nonnull {
|
||||
FIRInstallationsIDController *strongSelf = weakSelf;
|
||||
return [strongSelf installationWithValidAuthTokenForcingRefresh:NO];
|
||||
}];
|
||||
|
||||
_authTokenForcingRefreshPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc]
|
||||
initWithNewOperationHandler:^FBLPromise *_Nonnull {
|
||||
FIRInstallationsIDController *strongSelf = weakSelf;
|
||||
return [strongSelf installationWithValidAuthTokenForcingRefresh:YES];
|
||||
}];
|
||||
|
||||
_deleteInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc]
|
||||
initWithNewOperationHandler:^FBLPromise *_Nonnull {
|
||||
FIRInstallationsIDController *strongSelf = weakSelf;
|
||||
return [strongSelf createDeleteInstallationPromise];
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Get Installation.
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)getInstallationItem {
|
||||
return [self.getInstallationPromiseCache getExistingPendingOrCreateNewPromise];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)createGetInstallationItemPromise {
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeNewGetInstallationOperationCreated, @"%s, appName: %@",
|
||||
__PRETTY_FUNCTION__, self.appName);
|
||||
|
||||
FBLPromise<FIRInstallationsItem *> *installationItemPromise =
|
||||
[self getStoredInstallation].recover(^id(NSError *error) {
|
||||
return [self createAndSaveFID];
|
||||
});
|
||||
|
||||
// Initiate registration process on success if needed, but return the installation without waiting
|
||||
// for it.
|
||||
installationItemPromise.then(^id(FIRInstallationsItem *installation) {
|
||||
[self getAuthTokenForcingRefresh:NO];
|
||||
return nil;
|
||||
});
|
||||
|
||||
return installationItemPromise;
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)getStoredInstallation {
|
||||
return [self.installationsStore installationForAppID:self.appID appName:self.appName].validate(
|
||||
^BOOL(FIRInstallationsItem *installation) {
|
||||
BOOL isValid = NO;
|
||||
switch (installation.registrationStatus) {
|
||||
case FIRInstallationStatusUnregistered:
|
||||
case FIRInstallationStatusRegistered:
|
||||
isValid = YES;
|
||||
break;
|
||||
|
||||
case FIRInstallationStatusUnknown:
|
||||
isValid = NO;
|
||||
break;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)createAndSaveFID {
|
||||
return [self migrateOrGenerateInstallation]
|
||||
.then(^FBLPromise<FIRInstallationsItem *> *(FIRInstallationsItem *installation) {
|
||||
return [self saveInstallation:installation];
|
||||
})
|
||||
.then(^FIRInstallationsItem *(FIRInstallationsItem *installation) {
|
||||
[self postFIDDidChangeNotification];
|
||||
return installation;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)saveInstallation:(FIRInstallationsItem *)installation {
|
||||
return [self.installationsStore saveInstallation:installation].then(
|
||||
^FIRInstallationsItem *(NSNull *result) {
|
||||
return installation;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to migrate IID data stored by FirebaseInstanceID SDK or generates a new Installation ID if
|
||||
* not found.
|
||||
*/
|
||||
- (FBLPromise<FIRInstallationsItem *> *)migrateOrGenerateInstallation {
|
||||
if (![self isDefaultApp]) {
|
||||
// Existing IID should be used only for default FirebaseApp.
|
||||
FIRInstallationsItem *installation =
|
||||
[self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil];
|
||||
return [FBLPromise resolvedWith:installation];
|
||||
}
|
||||
|
||||
return [[[FBLPromise
|
||||
all:@[ [self.IIDStore existingIID], [self.IIDTokenStore existingIIDDefaultToken] ]]
|
||||
then:^id _Nullable(NSArray *_Nullable results) {
|
||||
NSString *existingIID = results[0];
|
||||
NSString *IIDDefaultToken = results[1];
|
||||
|
||||
return [self createInstallationWithFID:existingIID IIDDefaultToken:IIDDefaultToken];
|
||||
}] recover:^id _Nullable(NSError *_Nonnull error) {
|
||||
return [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (FIRInstallationsItem *)createInstallationWithFID:(NSString *)FID
|
||||
IIDDefaultToken:(nullable NSString *)IIDDefaultToken {
|
||||
FIRInstallationsItem *installation = [[FIRInstallationsItem alloc] initWithAppID:self.appID
|
||||
firebaseAppName:self.appName];
|
||||
installation.firebaseInstallationID = FID;
|
||||
installation.IIDDefaultToken = IIDDefaultToken;
|
||||
installation.registrationStatus = FIRInstallationStatusUnregistered;
|
||||
return installation;
|
||||
}
|
||||
|
||||
#pragma mark - FID registration
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)registerInstallationIfNeeded:
|
||||
(FIRInstallationsItem *)installation {
|
||||
switch (installation.registrationStatus) {
|
||||
case FIRInstallationStatusRegistered:
|
||||
// Already registered. Do nothing.
|
||||
return [FBLPromise resolvedWith:installation];
|
||||
|
||||
case FIRInstallationStatusUnknown:
|
||||
case FIRInstallationStatusUnregistered:
|
||||
// Registration required. Proceed.
|
||||
break;
|
||||
}
|
||||
|
||||
return [self.APIService registerInstallation:installation]
|
||||
.catch(^(NSError *_Nonnull error) {
|
||||
if ([self doesRegistrationErrorRequireConfigChange:error]) {
|
||||
FIRLogError(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeInvalidFirebaseConfiguration,
|
||||
@"Firebase Installation registration failed for app with name: %@, error: "
|
||||
@"%@\nPlease make sure you use valid GoogleService-Info.plist",
|
||||
self.appName, error);
|
||||
}
|
||||
})
|
||||
.then(^id(FIRInstallationsItem *registeredInstallation) {
|
||||
return [self saveInstallation:registeredInstallation];
|
||||
})
|
||||
.then(^FIRInstallationsItem *(FIRInstallationsItem *registeredInstallation) {
|
||||
// Server may respond with a different FID if the sent one cannot be accepted.
|
||||
if (![registeredInstallation.firebaseInstallationID
|
||||
isEqualToString:installation.firebaseInstallationID]) {
|
||||
[self postFIDDidChangeNotification];
|
||||
}
|
||||
return registeredInstallation;
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL)doesRegistrationErrorRequireConfigChange:(NSError *)error {
|
||||
FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error;
|
||||
if (![HTTPError isKindOfClass:[FIRInstallationsHTTPError class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
switch (HTTPError.HTTPResponse.statusCode) {
|
||||
// These are the errors that require Firebase configuration change.
|
||||
case FIRInstallationsRegistrationHTTPCodeInvalidArgument:
|
||||
case FIRInstallationsRegistrationHTTPCodeInvalidAPIKey:
|
||||
case FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch:
|
||||
case FIRInstallationsRegistrationHTTPCodeProjectNotFound:
|
||||
return YES;
|
||||
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Auth Token
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)getAuthTokenForcingRefresh:(BOOL)forceRefresh {
|
||||
if (forceRefresh || [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] != nil) {
|
||||
return [self.authTokenForcingRefreshPromiseCache getExistingPendingOrCreateNewPromise];
|
||||
} else {
|
||||
return [self.authTokenPromiseCache getExistingPendingOrCreateNewPromise];
|
||||
}
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)installationWithValidAuthTokenForcingRefresh:
|
||||
(BOOL)forceRefresh {
|
||||
FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated,
|
||||
@"-[FIRInstallationsIDController installationWithValidAuthTokenForcingRefresh:%@], "
|
||||
@"appName: %@",
|
||||
@(forceRefresh), self.appName);
|
||||
|
||||
return [self getInstallationItem]
|
||||
.then(^FBLPromise<FIRInstallationsItem *> *(FIRInstallationsItem *installation) {
|
||||
return [self registerInstallationIfNeeded:installation];
|
||||
})
|
||||
.then(^id(FIRInstallationsItem *registeredInstallation) {
|
||||
BOOL isTokenExpiredOrExpiresSoon =
|
||||
[registeredInstallation.authToken.expirationDate timeIntervalSinceDate:[NSDate date]] <
|
||||
kFIRInstallationsTokenExpirationThreshold;
|
||||
if (forceRefresh || isTokenExpiredOrExpiresSoon) {
|
||||
return [self refreshAuthTokenForInstallation:registeredInstallation];
|
||||
} else {
|
||||
return registeredInstallation;
|
||||
}
|
||||
})
|
||||
.recover(^id(NSError *error) {
|
||||
return [self regenerateFIDOnRefreshTokenErrorIfNeeded:error];
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)refreshAuthTokenForInstallation:
|
||||
(FIRInstallationsItem *)installation {
|
||||
return [[self.APIService refreshAuthTokenForInstallation:installation]
|
||||
then:^id _Nullable(FIRInstallationsItem *_Nullable refreshedInstallation) {
|
||||
return [self saveInstallation:refreshedInstallation];
|
||||
}];
|
||||
}
|
||||
|
||||
- (id)regenerateFIDOnRefreshTokenErrorIfNeeded:(NSError *)error {
|
||||
if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) {
|
||||
// No recovery possible. Return the same error.
|
||||
return error;
|
||||
}
|
||||
|
||||
FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error;
|
||||
switch (HTTPError.HTTPResponse.statusCode) {
|
||||
case FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication:
|
||||
case FIRInstallationsAuthTokenHTTPCodeFIDNotFound:
|
||||
// The stored installation was damaged or blocked by the server.
|
||||
// Delete the stored installation then generate and register a new one.
|
||||
return [self getInstallationItem]
|
||||
.then(^FBLPromise<NSNull *> *(FIRInstallationsItem *installation) {
|
||||
return [self deleteInstallationLocally:installation];
|
||||
})
|
||||
.then(^FBLPromise<FIRInstallationsItem *> *(id result) {
|
||||
return [self installationWithValidAuthTokenForcingRefresh:NO];
|
||||
});
|
||||
|
||||
default:
|
||||
// No recovery possible. Return the same error.
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Delete FID
|
||||
|
||||
- (FBLPromise<NSNull *> *)deleteInstallation {
|
||||
return [self.deleteInstallationPromiseCache getExistingPendingOrCreateNewPromise];
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)createDeleteInstallationPromise {
|
||||
FIRLogDebug(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated, @"%s, appName: %@",
|
||||
__PRETTY_FUNCTION__, self.appName);
|
||||
|
||||
// Check for ongoing requests first, if there is no a request, then check local storage for
|
||||
// existing installation.
|
||||
FBLPromise<FIRInstallationsItem *> *currentInstallationPromise =
|
||||
[self mostRecentInstallationOperation] ?: [self getStoredInstallation];
|
||||
|
||||
return currentInstallationPromise
|
||||
.then(^id(FIRInstallationsItem *installation) {
|
||||
return [self sendDeleteInstallationRequestIfNeeded:installation];
|
||||
})
|
||||
.then(^id(FIRInstallationsItem *installation) {
|
||||
// Remove the installation from the local storage.
|
||||
return [self deleteInstallationLocally:installation];
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)deleteInstallationLocally:(FIRInstallationsItem *)installation {
|
||||
return [self.installationsStore removeInstallationForAppID:installation.appID
|
||||
appName:installation.firebaseAppName]
|
||||
.then(^FBLPromise<NSNull *> *(NSNull *result) {
|
||||
return [self deleteExistingIIDIfNeeded];
|
||||
})
|
||||
.then(^NSNull *(NSNull *result) {
|
||||
[self postFIDDidChangeNotification];
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)sendDeleteInstallationRequestIfNeeded:
|
||||
(FIRInstallationsItem *)installation {
|
||||
switch (installation.registrationStatus) {
|
||||
case FIRInstallationStatusUnknown:
|
||||
case FIRInstallationStatusUnregistered:
|
||||
// The installation is not registered, so it is safe to be deleted as is, so return early.
|
||||
return [FBLPromise resolvedWith:installation];
|
||||
break;
|
||||
|
||||
case FIRInstallationStatusRegistered:
|
||||
// Proceed to de-register the installation on the server.
|
||||
break;
|
||||
}
|
||||
|
||||
return [self.APIService deleteInstallation:installation].recover(^id(NSError *APIError) {
|
||||
if ([FIRInstallationsErrorUtil isAPIError:APIError withHTTPCode:404]) {
|
||||
// The installation was not found on the server.
|
||||
// Return success.
|
||||
return installation;
|
||||
} else {
|
||||
// Re-throw the error otherwise.
|
||||
return APIError;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)deleteExistingIIDIfNeeded {
|
||||
if ([self isDefaultApp]) {
|
||||
return [self.IIDStore deleteExistingIID];
|
||||
} else {
|
||||
return [FBLPromise resolvedWith:[NSNull null]];
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable FBLPromise<FIRInstallationsItem *> *)mostRecentInstallationOperation {
|
||||
return [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise]
|
||||
?: [self.authTokenPromiseCache getExistingPendingPromise]
|
||||
?: [self.getInstallationPromiseCache getExistingPendingPromise];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)postFIDDidChangeNotification {
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:FIRInstallationIDDidChangeNotification
|
||||
object:nil
|
||||
userInfo:@{kFIRInstallationIDDidChangeNotificationAppNameKey : self.appName}];
|
||||
}
|
||||
|
||||
#pragma mark - Default App
|
||||
|
||||
- (BOOL)isDefaultApp {
|
||||
return [self.appName isEqualToString:kFIRDefaultAppName];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The class makes sure the a single operation (represented by a promise) is performed at a time. If
|
||||
* there is an ongoing operation, then its existing corresponding promise will be returned instead
|
||||
* of starting a new operation.
|
||||
*/
|
||||
@interface FIRInstallationsSingleOperationPromiseCache<__covariant ResultType> : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* The designated initializer.
|
||||
* @param newOperationHandler The block that must return a new promise representing the
|
||||
* single-at-a-time operation. The promise should be fulfilled when the operation is completed. The
|
||||
* factory block will be used to create a new promise when needed.
|
||||
*/
|
||||
- (instancetype)initWithNewOperationHandler:
|
||||
(FBLPromise<ResultType> *_Nonnull (^)(void))newOperationHandler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Creates a new promise or returns an existing pending one.
|
||||
* @return Returns and existing pending promise if exists. If the pending promise does not exist
|
||||
* then a new one will be created using the `factory` block passed in the initializer. Once the
|
||||
* pending promise gets resolved, it is removed, so calling the method again will lead to creating
|
||||
* and caching another promise.
|
||||
*/
|
||||
- (FBLPromise<ResultType> *)getExistingPendingOrCreateNewPromise;
|
||||
|
||||
/**
|
||||
* Returns an existing pending promise or `nil`.
|
||||
* @return Returns an existing pending promise if there is one or `nil` otherwise.
|
||||
*/
|
||||
- (nullable FBLPromise<ResultType> *)getExistingPendingPromise;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsSingleOperationPromiseCache.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
@interface FIRInstallationsSingleOperationPromiseCache <ResultType>()
|
||||
@property(nonatomic, readonly) FBLPromise *_Nonnull (^newOperationHandler)(void);
|
||||
@property(nonatomic, nullable) FBLPromise *pendingPromise;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsSingleOperationPromiseCache
|
||||
|
||||
- (instancetype)initWithNewOperationHandler:
|
||||
(FBLPromise<id> *_Nonnull (^)(void))newOperationHandler {
|
||||
if (newOperationHandler == nil) {
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"`newOperationHandler` must not be `nil`."];
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_newOperationHandler = [newOperationHandler copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (FBLPromise *)getExistingPendingOrCreateNewPromise {
|
||||
@synchronized(self) {
|
||||
if (!self.pendingPromise) {
|
||||
self.pendingPromise = self.newOperationHandler();
|
||||
|
||||
self.pendingPromise
|
||||
.then(^id(id result) {
|
||||
@synchronized(self) {
|
||||
self.pendingPromise = nil;
|
||||
return nil;
|
||||
}
|
||||
})
|
||||
.catch(^void(NSError *error) {
|
||||
@synchronized(self) {
|
||||
self.pendingPromise = nil;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return self.pendingPromise;
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable FBLPromise *)getExistingPendingPromise {
|
||||
@synchronized(self) {
|
||||
return self.pendingPromise;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* The enum represent possible states of the installation ID.
|
||||
*
|
||||
* WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredItem`. Modification
|
||||
* of it can lead to incompatibility with previous version. Any modification must be evaluated and,
|
||||
* if it is really needed, the `storageVersion` must be bumped and proper migration code added.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, FIRInstallationsStatus) {
|
||||
/** Represents either an initial status when a FIRInstallationsItem instance was created but not
|
||||
* stored to Keychain or an undefined status (e.g. when the status failed to deserialize).
|
||||
*/
|
||||
FIRInstallationStatusUnknown,
|
||||
/// The Firebase Installation has not yet been registered with FIS.
|
||||
FIRInstallationStatusUnregistered,
|
||||
/// The Firebase Installation has successfully been registered with FIS.
|
||||
FIRInstallationStatusRegistered,
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
@class FIRInstallationsItem;
|
||||
@class FIRSecureStorage;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// The user defaults suite name used to store data.
|
||||
extern NSString *const kFIRInstallationsStoreUserDefaultsID;
|
||||
|
||||
/// The class is responsible for storing and accessing the installations data.
|
||||
@interface FIRInstallationsStore : NSObject
|
||||
|
||||
/**
|
||||
* The default initializer.
|
||||
* @param storage The secure storage to save installations data.
|
||||
* @param accessGroup The Keychain Access Group to store and request the installations data.
|
||||
*/
|
||||
- (instancetype)initWithSecureStorage:(FIRSecureStorage *)storage
|
||||
accessGroup:(nullable NSString *)accessGroup;
|
||||
|
||||
/**
|
||||
* Retrieves existing installation ID if there is.
|
||||
* @param appID The Firebase(Google) Application ID.
|
||||
* @param appName The Firebase Application Name.
|
||||
*
|
||||
* @return Returns a `FBLPromise` instance. The promise is resolved with a FIRInstallationsItem
|
||||
* instance if there is a valid installation stored for `appID` and `appName`. The promise is
|
||||
* rejected with a specific error when the installation has not been found or with another possible
|
||||
* error.
|
||||
*/
|
||||
- (FBLPromise<FIRInstallationsItem *> *)installationForAppID:(NSString *)appID
|
||||
appName:(NSString *)appName;
|
||||
|
||||
/**
|
||||
* Saves the given installation.
|
||||
*
|
||||
* @param installationItem The installation data.
|
||||
* @return Returns a promise that is resolved with `[NSNull null]` on success.
|
||||
*/
|
||||
- (FBLPromise<NSNull *> *)saveInstallation:(FIRInstallationsItem *)installationItem;
|
||||
|
||||
/**
|
||||
* Removes installation data for the given app parameters.
|
||||
* @param appID The Firebase(Google) Application ID.
|
||||
* @param appName The Firebase Application Name.
|
||||
*
|
||||
* @return Returns a promise that is resolved with `[NSNull null]` on success.
|
||||
*/
|
||||
- (FBLPromise<NSNull *> *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsStore.h"
|
||||
|
||||
#import <GoogleUtilities/GULUserDefaults.h>
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
#else
|
||||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
#import "FIRInstallationsItem.h"
|
||||
#import "FIRInstallationsStoredItem.h"
|
||||
#import "FIRSecureStorage.h"
|
||||
|
||||
NSString *const kFIRInstallationsStoreUserDefaultsID = @"com.firebase.FIRInstallations";
|
||||
|
||||
@interface FIRInstallationsStore ()
|
||||
@property(nonatomic, readonly) FIRSecureStorage *secureStorage;
|
||||
@property(nonatomic, readonly, nullable) NSString *accessGroup;
|
||||
@property(nonatomic, readonly) dispatch_queue_t queue;
|
||||
@property(nonatomic, readonly) GULUserDefaults *userDefaults;
|
||||
@end
|
||||
|
||||
@implementation FIRInstallationsStore
|
||||
|
||||
- (instancetype)initWithSecureStorage:(FIRSecureStorage *)storage
|
||||
accessGroup:(NSString *)accessGroup {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_secureStorage = storage;
|
||||
_accessGroup = [accessGroup copy];
|
||||
_queue = dispatch_queue_create("com.firebase.FIRInstallationsStore", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
NSString *userDefaultsSuiteName = _accessGroup ?: kFIRInstallationsStoreUserDefaultsID;
|
||||
_userDefaults = [[GULUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRInstallationsItem *> *)installationForAppID:(NSString *)appID
|
||||
appName:(NSString *)appName {
|
||||
NSString *itemID = [FIRInstallationsItem identifierWithAppID:appID appName:appName];
|
||||
return [self installationExistsForAppID:appID appName:appName]
|
||||
.then(^id(id result) {
|
||||
return [self.secureStorage getObjectForKey:itemID
|
||||
objectClass:[FIRInstallationsStoredItem class]
|
||||
accessGroup:self.accessGroup];
|
||||
})
|
||||
.then(^id(FIRInstallationsStoredItem *_Nullable storedItem) {
|
||||
if (storedItem == nil) {
|
||||
return [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID appName:appName];
|
||||
}
|
||||
|
||||
FIRInstallationsItem *item = [[FIRInstallationsItem alloc] initWithAppID:appID
|
||||
firebaseAppName:appName];
|
||||
[item updateWithStoredItem:storedItem];
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)saveInstallation:(FIRInstallationsItem *)installationItem {
|
||||
FIRInstallationsStoredItem *storedItem = [installationItem storedItem];
|
||||
NSString *identifier = [installationItem identifier];
|
||||
|
||||
return
|
||||
[self.secureStorage setObject:storedItem forKey:identifier accessGroup:self.accessGroup].then(
|
||||
^id(id result) {
|
||||
return [self setInstallationExists:YES forItemWithIdentifier:identifier];
|
||||
});
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName {
|
||||
NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName];
|
||||
return [self.secureStorage removeObjectForKey:identifier accessGroup:self.accessGroup].then(
|
||||
^id(id result) {
|
||||
return [self setInstallationExists:NO forItemWithIdentifier:identifier];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - User defaults
|
||||
|
||||
- (FBLPromise<NSNull *> *)installationExistsForAppID:(NSString *)appID appName:(NSString *)appName {
|
||||
NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName];
|
||||
return [FBLPromise onQueue:self.queue
|
||||
do:^id _Nullable {
|
||||
return [[self userDefaults] objectForKey:identifier] != nil
|
||||
? [NSNull null]
|
||||
: [FIRInstallationsErrorUtil
|
||||
installationItemNotFoundForAppID:appID
|
||||
appName:appName];
|
||||
}];
|
||||
}
|
||||
|
||||
- (FBLPromise<NSNull *> *)setInstallationExists:(BOOL)exists
|
||||
forItemWithIdentifier:(NSString *)identifier {
|
||||
return [FBLPromise onQueue:self.queue
|
||||
do:^id _Nullable {
|
||||
if (exists) {
|
||||
[[self userDefaults] setBool:YES forKey:identifier];
|
||||
} else {
|
||||
[[self userDefaults] removeObjectForKey:identifier];
|
||||
}
|
||||
|
||||
return [NSNull null];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The enum represent possible states of the installation auth token.
|
||||
*
|
||||
* WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredAuthToken`.
|
||||
* Modification of it can lead to incompatibility with previous version. Any modification must be
|
||||
* evaluated and, if it is really needed, the `storageVersion` must be bumped and proper migration
|
||||
* code added.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenStatus) {
|
||||
/// An initial status or an undefined value.
|
||||
FIRInstallationsAuthTokenStatusUnknown,
|
||||
/// The auth token has been received from the server.
|
||||
FIRInstallationsAuthTokenStatusTokenReceived
|
||||
};
|
||||
|
||||
/**
|
||||
* This class serializes and deserializes the installation data into/from `NSData` to be stored in
|
||||
* Keychain. This class is primarily used by `FIRInstallationsStore`. It is also used on the logic
|
||||
* level as a data object (see `FIRInstallationsItem.authToken`).
|
||||
*
|
||||
* WARNING: Modification of the class properties can lead to incompatibility with the stored data
|
||||
* encoded by the previous class versions. Any modification must be evaluated and, if it is really
|
||||
* needed, the `storageVersion` must be bumped and proper migration code added.
|
||||
*/
|
||||
@interface FIRInstallationsStoredAuthToken : NSObject <NSSecureCoding, NSCopying>
|
||||
@property FIRInstallationsAuthTokenStatus status;
|
||||
|
||||
/// The token that can be used to authorize requests to Firebase backend.
|
||||
@property(nullable, copy) NSString *token;
|
||||
/// The date when the auth token expires.
|
||||
@property(nullable, copy) NSDate *expirationDate;
|
||||
|
||||
/// The version of local storage.
|
||||
@property(nonatomic, readonly) NSInteger storageVersion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
|
||||
#import "FIRInstallationsLogger.h"
|
||||
|
||||
NSString *const kFIRInstallationsStoredAuthTokenStatusKey = @"status";
|
||||
NSString *const kFIRInstallationsStoredAuthTokenTokenKey = @"token";
|
||||
NSString *const kFIRInstallationsStoredAuthTokenExpirationDateKey = @"expirationDate";
|
||||
NSString *const kFIRInstallationsStoredAuthTokenStorageVersionKey = @"storageVersion";
|
||||
|
||||
NSInteger const kFIRInstallationsStoredAuthTokenStorageVersion = 1;
|
||||
|
||||
@implementation FIRInstallationsStoredAuthToken
|
||||
|
||||
- (NSInteger)storageVersion {
|
||||
return kFIRInstallationsStoredAuthTokenStorageVersion;
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
|
||||
FIRInstallationsStoredAuthToken *clone = [[FIRInstallationsStoredAuthToken alloc] init];
|
||||
clone.status = self.status;
|
||||
clone.token = [self.token copy];
|
||||
clone.expirationDate = self.expirationDate;
|
||||
return clone;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:self.status forKey:kFIRInstallationsStoredAuthTokenStatusKey];
|
||||
[aCoder encodeObject:self.token forKey:kFIRInstallationsStoredAuthTokenTokenKey];
|
||||
[aCoder encodeObject:self.expirationDate
|
||||
forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey];
|
||||
[aCoder encodeInteger:self.storageVersion
|
||||
forKey:kFIRInstallationsStoredAuthTokenStorageVersionKey];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
|
||||
NSInteger storageVersion =
|
||||
[aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStorageVersionKey];
|
||||
if (storageVersion > kFIRInstallationsStoredAuthTokenStorageVersion) {
|
||||
FIRLogWarning(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch,
|
||||
@"FIRInstallationsStoredAuthToken was encoded by a newer coder version %ld. "
|
||||
@"Current coder version is %ld. Some auth token data may be lost.",
|
||||
(long)storageVersion, (long)kFIRInstallationsStoredAuthTokenStorageVersion);
|
||||
}
|
||||
|
||||
FIRInstallationsStoredAuthToken *object = [[FIRInstallationsStoredAuthToken alloc] init];
|
||||
object.status = [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStatusKey];
|
||||
object.token = [aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kFIRInstallationsStoredAuthTokenTokenKey];
|
||||
object.expirationDate =
|
||||
[aDecoder decodeObjectOfClass:[NSDate class]
|
||||
forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FIRInstallationsStatus.h"
|
||||
|
||||
@class FIRInstallationsStoredAuthToken;
|
||||
@class FIRInstallationsStoredIIDCheckin;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The class is supposed to be used by `FIRInstallationsStore` only. It is required to
|
||||
* serialize/deserialize the installation data into/from `NSData` to be stored in Keychain.
|
||||
*
|
||||
* WARNING: Modification of the class properties can lead to incompatibility with the stored data
|
||||
* encoded by the previous class versions. Any modification must be evaluated and, if it is really
|
||||
* needed, the `storageVersion` must be bumped and proper migration code added.
|
||||
*/
|
||||
@interface FIRInstallationsStoredItem : NSObject <NSSecureCoding>
|
||||
|
||||
/// A stable identifier that uniquely identifies the app instance.
|
||||
@property(nonatomic, copy, nullable) NSString *firebaseInstallationID;
|
||||
/// The `refreshToken` is used to authorize the auth token requests.
|
||||
@property(nonatomic, copy, nullable) NSString *refreshToken;
|
||||
|
||||
@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken;
|
||||
@property(nonatomic) FIRInstallationsStatus registrationStatus;
|
||||
|
||||
/// Instance ID default auth token imported from IID store as a part of IID migration.
|
||||
@property(nonatomic, nullable) NSString *IIDDefaultToken;
|
||||
|
||||
/// The version of local storage.
|
||||
@property(nonatomic, readonly) NSInteger storageVersion;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsStoredItem.h"
|
||||
|
||||
#import "FIRInstallationsLogger.h"
|
||||
#import "FIRInstallationsStoredAuthToken.h"
|
||||
|
||||
NSString *const kFIRInstallationsStoredItemFirebaseInstallationIDKey = @"firebaseInstallationID";
|
||||
NSString *const kFIRInstallationsStoredItemRefreshTokenKey = @"refreshToken";
|
||||
NSString *const kFIRInstallationsStoredItemAuthTokenKey = @"authToken";
|
||||
NSString *const kFIRInstallationsStoredItemRegistrationStatusKey = @"registrationStatus";
|
||||
NSString *const kFIRInstallationsStoredItemIIDDefaultTokenKey = @"IIDDefaultToken";
|
||||
NSString *const kFIRInstallationsStoredItemStorageVersionKey = @"storageVersion";
|
||||
|
||||
NSInteger const kFIRInstallationsStoredItemStorageVersion = 1;
|
||||
|
||||
@implementation FIRInstallationsStoredItem
|
||||
|
||||
- (NSInteger)storageVersion {
|
||||
return kFIRInstallationsStoredItemStorageVersion;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.firebaseInstallationID
|
||||
forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey];
|
||||
[aCoder encodeObject:self.refreshToken forKey:kFIRInstallationsStoredItemRefreshTokenKey];
|
||||
[aCoder encodeObject:self.authToken forKey:kFIRInstallationsStoredItemAuthTokenKey];
|
||||
[aCoder encodeInteger:self.registrationStatus
|
||||
forKey:kFIRInstallationsStoredItemRegistrationStatusKey];
|
||||
[aCoder encodeObject:self.IIDDefaultToken forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey];
|
||||
[aCoder encodeInteger:self.storageVersion forKey:kFIRInstallationsStoredItemStorageVersionKey];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
|
||||
NSInteger storageVersion =
|
||||
[aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemStorageVersionKey];
|
||||
if (storageVersion > self.storageVersion) {
|
||||
FIRLogWarning(kFIRLoggerInstallations,
|
||||
kFIRInstallationsMessageCodeInstallationCoderVersionMismatch,
|
||||
@"FIRInstallationsStoredItem was encoded by a newer coder version %ld. Current "
|
||||
@"coder version is %ld. Some installation data may be lost.",
|
||||
(long)storageVersion, (long)kFIRInstallationsStoredItemStorageVersion);
|
||||
}
|
||||
|
||||
FIRInstallationsStoredItem *item = [[FIRInstallationsStoredItem alloc] init];
|
||||
item.firebaseInstallationID =
|
||||
[aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey];
|
||||
item.refreshToken = [aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kFIRInstallationsStoredItemRefreshTokenKey];
|
||||
item.authToken = [aDecoder decodeObjectOfClass:[FIRInstallationsStoredAuthToken class]
|
||||
forKey:kFIRInstallationsStoredItemAuthTokenKey];
|
||||
item.registrationStatus =
|
||||
[aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemRegistrationStatusKey];
|
||||
item.IIDDefaultToken =
|
||||
[aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
120
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallations.h
generated
Normal file
120
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallations.h
generated
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FIRApp;
|
||||
@class FIRInstallationsAuthTokenResult;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** A notification with this name is sent each time an installation is created or deleted. */
|
||||
FOUNDATION_EXPORT const NSNotificationName FIRInstallationIDDidChangeNotification;
|
||||
/** `userInfo` key for the `FirebaseApp.name` in `FIRInstallationIDDidChangeNotification`. */
|
||||
FOUNDATION_EXPORT NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey;
|
||||
|
||||
/**
|
||||
* An installation ID handler block.
|
||||
* @param identifier The installation ID string if exists or `nil` otherwise.
|
||||
* @param error The error when `identifier == nil` or `nil` otherwise.
|
||||
*/
|
||||
typedef void (^FIRInstallationsIDHandler)(NSString *__nullable identifier,
|
||||
NSError *__nullable error)
|
||||
NS_SWIFT_NAME(InstallationsIDHandler);
|
||||
|
||||
/**
|
||||
* An authorization token handler block.
|
||||
* @param tokenResult An instance of `InstallationsAuthTokenResult` in case of success or `nil`
|
||||
* otherwise.
|
||||
* @param error The error when `tokenResult == nil` or `nil` otherwise.
|
||||
*/
|
||||
typedef void (^FIRInstallationsTokenHandler)(
|
||||
FIRInstallationsAuthTokenResult *__nullable tokenResult, NSError *__nullable error)
|
||||
NS_SWIFT_NAME(InstallationsTokenHandler);
|
||||
|
||||
/**
|
||||
* The class provides API for Firebase Installations.
|
||||
* Each configured `FirebaseApp` has a corresponding single instance of `Installations`.
|
||||
* An instance of the class provides access to the installation info for the `FirebaseApp` as well
|
||||
* as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and
|
||||
* `FirebaseApp.options.googleAppID` .
|
||||
*/
|
||||
NS_SWIFT_NAME(Installations)
|
||||
@interface FIRInstallations : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Returns a default instance of `Installations`.
|
||||
* @returns An instance of `Installations` for `FirebaseApp.defaultApp().
|
||||
* @throw Throws an exception if the default app is not configured yet or required `FirebaseApp`
|
||||
* options are missing.
|
||||
*/
|
||||
+ (FIRInstallations *)installations NS_SWIFT_NAME(installations());
|
||||
|
||||
/**
|
||||
* Returns an instance of `Installations` for an application.
|
||||
* @param application A configured `FirebaseApp` instance.
|
||||
* @returns An instance of `Installations` corresponding to the passed application.
|
||||
* @throw Throws an exception if required `FirebaseApp` options are missing.
|
||||
*/
|
||||
+ (FIRInstallations *)installationsWithApp:(FIRApp *)application NS_SWIFT_NAME(installations(app:));
|
||||
|
||||
/**
|
||||
* The method creates or retrieves an installation ID. The installation ID is a stable identifier
|
||||
* that uniquely identifies the app instance. NOTE: If the application already has an existing
|
||||
* FirebaseInstanceID then the InstanceID identifier will be used.
|
||||
* @param completion A completion handler which is invoked when the operation completes. See
|
||||
* `InstallationsIDHandler` for additional details.
|
||||
*/
|
||||
- (void)installationIDWithCompletion:(FIRInstallationsIDHandler)completion;
|
||||
|
||||
/**
|
||||
* Retrieves (locally if it exists or from the server) a valid authorization token. An existing
|
||||
* token may be invalidated or expired, so it is recommended to fetch the auth token before each
|
||||
* server request. The method does the same as `Installations.authTokenForcingRefresh(:,
|
||||
* completion:)` with forcing refresh `NO`.
|
||||
* @param completion A completion handler which is invoked when the operation completes. See
|
||||
* `InstallationsTokenHandler` for additional details.
|
||||
*/
|
||||
- (void)authTokenWithCompletion:(FIRInstallationsTokenHandler)completion;
|
||||
|
||||
/**
|
||||
* Retrieves (locally or from the server depending on `forceRefresh` value) a valid authorization
|
||||
* token. An existing token may be invalidated or expire, so it is recommended to fetch the auth
|
||||
* token before each server request. This method should be used with `forceRefresh == YES` when e.g.
|
||||
* a request with the previously fetched auth token failed with "Not Authorized" error.
|
||||
* @param forceRefresh If `YES` then the locally cached auth token will be ignored and a new one
|
||||
* will be requested from the server. If `NO`, then the locally cached auth token will be returned
|
||||
* if exists and has not expired yet.
|
||||
* @param completion A completion handler which is invoked when the operation completes. See
|
||||
* `InstallationsTokenHandler` for additional details.
|
||||
*/
|
||||
- (void)authTokenForcingRefresh:(BOOL)forceRefresh
|
||||
completion:(FIRInstallationsTokenHandler)completion;
|
||||
|
||||
/**
|
||||
* Deletes all the installation data including the unique identifier, auth tokens and
|
||||
* all related data on the server side. A network connection is required for the method to
|
||||
* succeed. If fails, the existing installation data remains untouched.
|
||||
* @param completion A completion handler which is invoked when the operation completes. `error ==
|
||||
* nil` indicates success.
|
||||
*/
|
||||
- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** The class represents a result of the auth token request. */
|
||||
NS_SWIFT_NAME(InstallationsAuthTokenResult)
|
||||
@interface FIRInstallationsAuthTokenResult : NSObject
|
||||
|
||||
/** The authorization token string. */
|
||||
@property(nonatomic, readonly) NSString *authToken;
|
||||
|
||||
/** The auth token expiration date. */
|
||||
@property(nonatomic, readonly) NSDate *expirationDate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
34
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallationsErrors.h
generated
Normal file
34
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallationsErrors.h
generated
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString *const kFirebaseInstallationsErrorDomain;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FIRInstallationsErrorCode) {
|
||||
/** Unknown error. See `userInfo` for details. */
|
||||
FIRInstallationsErrorCodeUnknown = 0,
|
||||
|
||||
/** Keychain error. See `userInfo` for details. */
|
||||
FIRInstallationsErrorCodeKeychain = 1,
|
||||
|
||||
/** Server unreachable. A network error or server is unavailable. See `userInfo` for details. */
|
||||
FIRInstallationsErrorCodeServerUnreachable = 2,
|
||||
|
||||
/** FirebaseApp configuration issues e.g. invalid GMP-App-ID, etc. See `userInfo` for details. */
|
||||
FIRInstallationsErrorCodeInvalidConfiguration = 3,
|
||||
|
||||
} NS_SWIFT_NAME(InstallationsErrorCode);
|
19
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallationsVersion.h
generated
Normal file
19
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FIRInstallationsVersion.h
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
FOUNDATION_EXPORT const char *const FIRInstallationsVersionStr;
|
20
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations.h
generated
Normal file
20
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations.h
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallations.h"
|
||||
#import "FIRInstallationsAuthTokenResult.h"
|
||||
#import "FIRInstallationsErrors.h"
|
||||
#import "FIRInstallationsVersion.h"
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Helper functions to access Keychain.
|
||||
@interface FIRInstallationsKeychainUtils : NSObject
|
||||
|
||||
+ (nullable NSData *)getItemWithQuery:(NSDictionary *)query
|
||||
error:(NSError *_Nullable *_Nullable)outError;
|
||||
|
||||
+ (BOOL)setItem:(NSData *)item
|
||||
withQuery:(NSDictionary *)query
|
||||
error:(NSError *_Nullable *_Nullable)outError;
|
||||
|
||||
+ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRInstallationsKeychainUtils.h"
|
||||
|
||||
#import "FIRInstallationsErrorUtil.h"
|
||||
|
||||
@implementation FIRInstallationsKeychainUtils
|
||||
|
||||
+ (nullable NSData *)getItemWithQuery:(NSDictionary *)query
|
||||
error:(NSError *_Nullable *_Nullable)outError {
|
||||
NSMutableDictionary *mutableQuery = [query mutableCopy];
|
||||
|
||||
mutableQuery[(__bridge id)kSecReturnData] = @YES;
|
||||
mutableQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
|
||||
|
||||
CFDataRef result = NULL;
|
||||
OSStatus status =
|
||||
SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result);
|
||||
|
||||
if (status == errSecSuccess && result != NULL) {
|
||||
if (outError) {
|
||||
*outError = nil;
|
||||
}
|
||||
|
||||
return (__bridge_transfer NSData *)result;
|
||||
}
|
||||
|
||||
if (status == errSecItemNotFound) {
|
||||
if (outError) {
|
||||
*outError = nil;
|
||||
}
|
||||
} else {
|
||||
if (outError) {
|
||||
*outError = [FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemCopyMatching"
|
||||
status:status];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (BOOL)setItem:(NSData *)item
|
||||
withQuery:(NSDictionary *)query
|
||||
error:(NSError *_Nullable *_Nullable)outError {
|
||||
NSData *existingItem = [self getItemWithQuery:query error:outError];
|
||||
if (outError && *outError) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSMutableDictionary *mutableQuery = [query mutableCopy];
|
||||
mutableQuery[(__bridge id)kSecAttrAccessible] =
|
||||
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
|
||||
OSStatus status;
|
||||
if (!existingItem) {
|
||||
mutableQuery[(__bridge id)kSecValueData] = item;
|
||||
status = SecItemAdd((__bridge CFDictionaryRef)mutableQuery, NULL);
|
||||
} else {
|
||||
NSDictionary *attributes = @{(__bridge id)kSecValueData : item};
|
||||
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
|
||||
}
|
||||
|
||||
if (status == noErr) {
|
||||
if (outError) {
|
||||
*outError = nil;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd";
|
||||
if (outError) {
|
||||
*outError = [FIRInstallationsErrorUtil keychainErrorWithFunction:function status:status];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError {
|
||||
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
|
||||
|
||||
if (status == noErr || status == errSecItemNotFound) {
|
||||
if (outError) {
|
||||
*outError = nil;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (outError) {
|
||||
*outError = [FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemDelete"
|
||||
status:status];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
71
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/SecureStorage/FIRSecureStorage.h
generated
Normal file
71
ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/SecureStorage/FIRSecureStorage.h
generated
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class FBLPromise<ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// The class provides a convenient abstraction on top of the iOS Keychain API to save data.
|
||||
@interface FIRSecureStorage : NSObject
|
||||
|
||||
/**
|
||||
* Get an object by key.
|
||||
* @param key The key.
|
||||
* @param objectClass The expected object class required by `NSSecureCoding`.
|
||||
* @param accessGroup The Keychain Access Group.
|
||||
*
|
||||
* @return Returns a promise. It is resolved with an object stored by key if exists. It is resolved
|
||||
* with `nil` when the object not found. It fails on a Keychain error.
|
||||
*/
|
||||
- (FBLPromise<id<NSSecureCoding>> *)getObjectForKey:(NSString *)key
|
||||
objectClass:(Class)objectClass
|
||||
accessGroup:(nullable NSString *)accessGroup;
|
||||
|
||||
/**
|
||||
* Saves the given object by the given key.
|
||||
* @param object The object to store.
|
||||
* @param key The key to store the object. If there is an existing object by the key, it will be
|
||||
* overridden.
|
||||
* @param accessGroup The Keychain Access Group.
|
||||
*
|
||||
* @return Returns which is resolved with `[NSNull null]` on success.
|
||||
*/
|
||||
- (FBLPromise<NSNull *> *)setObject:(id<NSSecureCoding>)object
|
||||
forKey:(NSString *)key
|
||||
accessGroup:(nullable NSString *)accessGroup;
|
||||
|
||||
/**
|
||||
* Removes the object by the given key.
|
||||
* @param key The key to store the object. If there is an existing object by the key, it will be
|
||||
* overridden.
|
||||
* @param accessGroup The Keychain Access Group.
|
||||
*
|
||||
* @return Returns which is resolved with `[NSNull null]` on success.
|
||||
*/
|
||||
- (FBLPromise<NSNull *> *)removeObjectForKey:(NSString *)key
|
||||
accessGroup:(nullable NSString *)accessGroup;
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
/// If not `nil`, then only this keychain will be used to save and read data (see
|
||||
/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests.
|
||||
@property(nonatomic, nullable) SecKeychainRef keychainRef;
|
||||
#endif // TARGET_OSX
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue