[CHORE] Memory leaks investigation (#1675)
This commit is contained in:
parent
82fd91d2f4
commit
6a40d4cefb
|
@ -60,6 +60,8 @@ const emojiCount = (str) => {
|
||||||
return counter;
|
return counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parser = new Parser();
|
||||||
|
|
||||||
class Markdown extends PureComponent {
|
class Markdown extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
msg: PropTypes.string,
|
msg: PropTypes.string,
|
||||||
|
@ -81,13 +83,9 @@ class Markdown extends PureComponent {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.parser = this.createParser();
|
|
||||||
this.renderer = this.createRenderer(props.preview);
|
this.renderer = this.createRenderer(props.preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
createParser = () => new Parser();
|
|
||||||
|
|
||||||
createRenderer = (preview = false) => new Renderer({
|
createRenderer = (preview = false) => new Renderer({
|
||||||
renderers: {
|
renderers: {
|
||||||
text: this.renderText,
|
text: this.renderText,
|
||||||
|
@ -385,7 +383,7 @@ class Markdown extends PureComponent {
|
||||||
|
|
||||||
if (preview) {
|
if (preview) {
|
||||||
m = m.split('\n').reduce((lines, line) => `${ lines } ${ line }`, '');
|
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);
|
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>;
|
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.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
|
||||||
|
|
||||||
this.editedMessage(ast);
|
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 sharedStyles from './views/Styles';
|
||||||
import { SplitContext } from './split';
|
import { SplitContext } from './split';
|
||||||
|
|
||||||
|
import RoomsListView from './views/RoomsListView';
|
||||||
|
import RoomView from './views/RoomView';
|
||||||
|
|
||||||
if (isIOS) {
|
if (isIOS) {
|
||||||
const RNScreens = require('react-native-screens');
|
const RNScreens = require('react-native-screens');
|
||||||
RNScreens.useScreens();
|
RNScreens.useScreens();
|
||||||
|
@ -111,9 +114,7 @@ const OutsideStackModal = createStackNavigator({
|
||||||
});
|
});
|
||||||
|
|
||||||
const RoomRoutes = {
|
const RoomRoutes = {
|
||||||
RoomView: {
|
RoomView,
|
||||||
getScreen: () => require('./views/RoomView').default
|
|
||||||
},
|
|
||||||
ThreadMessagesView: {
|
ThreadMessagesView: {
|
||||||
getScreen: () => require('./views/ThreadMessagesView').default
|
getScreen: () => require('./views/ThreadMessagesView').default
|
||||||
},
|
},
|
||||||
|
@ -127,9 +128,7 @@ const RoomRoutes = {
|
||||||
|
|
||||||
// Inside
|
// Inside
|
||||||
const ChatsStack = createStackNavigator({
|
const ChatsStack = createStackNavigator({
|
||||||
RoomsListView: {
|
RoomsListView,
|
||||||
getScreen: () => require('./views/RoomsListView').default
|
|
||||||
},
|
|
||||||
RoomActionsView: {
|
RoomActionsView: {
|
||||||
getScreen: () => require('./views/RoomActionsView').default
|
getScreen: () => require('./views/RoomActionsView').default
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
import { InteractionManager } from 'react-native';
|
||||||
|
|
||||||
import database from '../../database';
|
import database from '../../database';
|
||||||
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
||||||
|
@ -23,7 +24,7 @@ let subQueue = {};
|
||||||
let subTimer = null;
|
let subTimer = null;
|
||||||
let roomQueue = {};
|
let roomQueue = {};
|
||||||
let roomTimer = null;
|
let roomTimer = null;
|
||||||
const WINDOW_TIME = 1000;
|
const WINDOW_TIME = 500;
|
||||||
|
|
||||||
const createOrUpdateSubscription = async(subscription, room) => {
|
const createOrUpdateSubscription = async(subscription, room) => {
|
||||||
try {
|
try {
|
||||||
|
@ -176,8 +177,10 @@ const debouncedUpdateSub = (subscription) => {
|
||||||
subQueue = {};
|
subQueue = {};
|
||||||
subTimer = null;
|
subTimer = null;
|
||||||
Object.keys(subBatch).forEach((key) => {
|
Object.keys(subBatch).forEach((key) => {
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
createOrUpdateSubscription(subBatch[key]);
|
createOrUpdateSubscription(subBatch[key]);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}, WINDOW_TIME);
|
}, WINDOW_TIME);
|
||||||
}
|
}
|
||||||
subQueue[subscription.rid] = subscription;
|
subQueue[subscription.rid] = subscription;
|
||||||
|
@ -190,8 +193,10 @@ const debouncedUpdateRoom = (room) => {
|
||||||
roomQueue = {};
|
roomQueue = {};
|
||||||
roomTimer = null;
|
roomTimer = null;
|
||||||
Object.keys(roomBatch).forEach((key) => {
|
Object.keys(roomBatch).forEach((key) => {
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
createOrUpdateSubscription(null, roomBatch[key]);
|
createOrUpdateSubscription(null, roomBatch[key]);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}, WINDOW_TIME);
|
}, WINDOW_TIME);
|
||||||
}
|
}
|
||||||
roomQueue[room._id] = room;
|
roomQueue[room._id] = room;
|
||||||
|
|
|
@ -25,9 +25,9 @@ class List extends React.Component {
|
||||||
rid: PropTypes.string,
|
rid: PropTypes.string,
|
||||||
t: PropTypes.string,
|
t: PropTypes.string,
|
||||||
tmid: PropTypes.string,
|
tmid: PropTypes.string,
|
||||||
animated: PropTypes.bool,
|
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
listRef: PropTypes.func
|
listRef: PropTypes.func,
|
||||||
|
navigation: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -40,9 +40,17 @@ class List extends React.Component {
|
||||||
loading: true,
|
loading: true,
|
||||||
end: false,
|
end: false,
|
||||||
messages: [],
|
messages: [],
|
||||||
refreshing: false
|
refreshing: false,
|
||||||
|
animated: false
|
||||||
};
|
};
|
||||||
this.init();
|
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`);
|
console.timeEnd(`${ this.constructor.name } init`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +138,9 @@ class List extends React.Component {
|
||||||
if (this.onEndReached && this.onEndReached.stop) {
|
if (this.onEndReached && this.onEndReached.stop) {
|
||||||
this.onEndReached.stop();
|
this.onEndReached.stop();
|
||||||
}
|
}
|
||||||
|
if (this.didFocusListener && this.didFocusListener.remove) {
|
||||||
|
this.didFocusListener.remove();
|
||||||
|
}
|
||||||
console.countReset(`${ this.constructor.name }.render calls`);
|
console.countReset(`${ this.constructor.name }.render calls`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +191,10 @@ class List extends React.Component {
|
||||||
|
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
update = () => {
|
update = () => {
|
||||||
|
const { animated } = this.state;
|
||||||
|
if (animated) {
|
||||||
animateNextTransition();
|
animateNextTransition();
|
||||||
|
}
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,8 +182,6 @@ class RoomView extends React.Component {
|
||||||
this.findAndObserveRoom(this.rid);
|
this.findAndObserveRoom(this.rid);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.beginAnimating = false;
|
|
||||||
this.didFocusListener = props.navigation.addListener('didFocus', () => this.beginAnimating = true);
|
|
||||||
this.messagebox = React.createRef();
|
this.messagebox = React.createRef();
|
||||||
this.list = React.createRef();
|
this.list = React.createRef();
|
||||||
this.willBlurListener = props.navigation.addListener('willBlur', () => this.mounted = false);
|
this.willBlurListener = props.navigation.addListener('willBlur', () => this.mounted = false);
|
||||||
|
@ -289,9 +287,6 @@ class RoomView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
if (this.didFocusListener && this.didFocusListener.remove) {
|
|
||||||
this.didFocusListener.remove();
|
|
||||||
}
|
|
||||||
if (this.didMountInteraction && this.didMountInteraction.cancel) {
|
if (this.didMountInteraction && this.didMountInteraction.cancel) {
|
||||||
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 });
|
navigation.navigate('RoomActionsView', { rid: this.rid, t: this.t, room });
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line react/sort-comp
|
|
||||||
init = async() => {
|
init = async() => {
|
||||||
try {
|
try {
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
@ -893,7 +887,9 @@ class RoomView extends React.Component {
|
||||||
const {
|
const {
|
||||||
room, reactionsModalVisible, selectedMessage, loading, reacting
|
room, reactionsModalVisible, selectedMessage, loading, reacting
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { user, baseUrl, theme } = this.props;
|
const {
|
||||||
|
user, baseUrl, theme, navigation
|
||||||
|
} = this.props;
|
||||||
const { rid, t } = room;
|
const { rid, t } = room;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -916,7 +912,7 @@ class RoomView extends React.Component {
|
||||||
room={room}
|
room={room}
|
||||||
renderRow={this.renderItem}
|
renderRow={this.renderItem}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
animated={this.beginAnimating}
|
navigation={navigation}
|
||||||
/>
|
/>
|
||||||
{this.renderFooter()}
|
{this.renderFooter()}
|
||||||
{this.renderActions()}
|
{this.renderActions()}
|
||||||
|
|
|
@ -182,6 +182,7 @@ class RoomsListView extends React.Component {
|
||||||
console.time(`${ this.constructor.name } mount`);
|
console.time(`${ this.constructor.name } mount`);
|
||||||
|
|
||||||
this.gotSubscriptions = false;
|
this.gotSubscriptions = false;
|
||||||
|
this.animated = false;
|
||||||
const { width } = Dimensions.get('window');
|
const { width } = Dimensions.get('window');
|
||||||
this.state = {
|
this.state = {
|
||||||
searching: false,
|
searching: false,
|
||||||
|
@ -215,9 +216,11 @@ class RoomsListView extends React.Component {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.didFocusListener = navigation.addListener('didFocus', () => {
|
this.didFocusListener = navigation.addListener('didFocus', () => {
|
||||||
|
this.animated = true;
|
||||||
this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||||
});
|
});
|
||||||
this.willBlurListener = navigation.addListener('willBlur', () => {
|
this.willBlurListener = navigation.addListener('willBlur', () => {
|
||||||
|
this.animated = false;
|
||||||
closeServerDropdown();
|
closeServerDropdown();
|
||||||
if (this.backHandler && this.backHandler.remove) {
|
if (this.backHandler && this.backHandler.remove) {
|
||||||
this.backHandler.remove();
|
this.backHandler.remove();
|
||||||
|
@ -338,12 +341,11 @@ class RoomsListView extends React.Component {
|
||||||
console.countReset(`${ this.constructor.name }.render calls`);
|
console.countReset(`${ this.constructor.name }.render calls`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/sort-comp
|
||||||
onDimensionsChange = ({ window: { width } }) => this.setState({ width });
|
onDimensionsChange = ({ window: { width } }) => this.setState({ width });
|
||||||
|
|
||||||
// eslint-disable-next-line react/sort-comp
|
|
||||||
internalSetState = (...args) => {
|
internalSetState = (...args) => {
|
||||||
const { navigation } = this.props;
|
if (this.animated) {
|
||||||
if (navigation.isFocused()) {
|
|
||||||
animateNextTransition();
|
animateNextTransition();
|
||||||
}
|
}
|
||||||
this.setState(...args);
|
this.setState(...args);
|
||||||
|
@ -532,7 +534,7 @@ class RoomsListView extends React.Component {
|
||||||
prid: item.prid,
|
prid: item.prid,
|
||||||
room: item
|
room: item
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
_onPressItem = async(item = {}) => {
|
_onPressItem = async(item = {}) => {
|
||||||
if (!item.search) {
|
if (!item.search) {
|
||||||
|
|
149
ios/Podfile.lock
149
ios/Podfile.lock
|
@ -34,35 +34,41 @@ PODS:
|
||||||
- React-Core (= 0.61.5)
|
- React-Core (= 0.61.5)
|
||||||
- React-jsi (= 0.61.5)
|
- React-jsi (= 0.61.5)
|
||||||
- ReactCommon/turbomodule/core (= 0.61.5)
|
- ReactCommon/turbomodule/core (= 0.61.5)
|
||||||
- Firebase/Core (6.8.1):
|
- Firebase/Core (6.16.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAnalytics (= 6.1.1)
|
- FirebaseAnalytics (= 6.2.2)
|
||||||
- Firebase/CoreOnly (6.8.1):
|
- Firebase/CoreOnly (6.16.0):
|
||||||
- FirebaseCore (= 6.2.3)
|
- FirebaseCore (= 6.6.1)
|
||||||
- FirebaseAnalytics (6.1.1):
|
- FirebaseAnalytics (6.2.2):
|
||||||
- FirebaseCore (~> 6.2)
|
- FirebaseCore (~> 6.6)
|
||||||
- FirebaseInstanceID (~> 4.2)
|
- FirebaseInstanceID (~> 4.3)
|
||||||
- GoogleAppMeasurement (= 6.1.1)
|
- GoogleAppMeasurement (= 6.2.2)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- GoogleUtilities/Network (~> 6.0)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||||
- nanopb (~> 0.3)
|
- nanopb (= 0.3.9011)
|
||||||
- FirebaseCore (6.2.3):
|
- FirebaseCore (6.6.1):
|
||||||
- FirebaseCoreDiagnostics (~> 1.0)
|
- FirebaseCoreDiagnostics (~> 1.2)
|
||||||
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||||
- GoogleUtilities/Environment (~> 6.2)
|
- GoogleUtilities/Environment (~> 6.5)
|
||||||
- GoogleUtilities/Logger (~> 6.2)
|
- GoogleUtilities/Logger (~> 6.5)
|
||||||
- FirebaseCoreDiagnostics (1.0.1):
|
- FirebaseCoreDiagnostics (1.2.0):
|
||||||
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||||
- GoogleDataTransportCCTSupport (~> 1.0)
|
- GoogleDataTransportCCTSupport (~> 1.3)
|
||||||
- GoogleUtilities/Environment (~> 6.2)
|
- GoogleUtilities/Environment (~> 6.5)
|
||||||
- GoogleUtilities/Logger (~> 6.2)
|
- GoogleUtilities/Logger (~> 6.5)
|
||||||
- FirebaseCoreDiagnosticsInterop (1.0.0)
|
- nanopb (~> 0.3.901)
|
||||||
- FirebaseInstanceID (4.2.5):
|
- FirebaseCoreDiagnosticsInterop (1.2.0)
|
||||||
- FirebaseCore (~> 6.0)
|
- FirebaseInstallations (1.1.0):
|
||||||
- GoogleUtilities/Environment (~> 6.0)
|
- FirebaseCore (~> 6.6)
|
||||||
- GoogleUtilities/UserDefaults (~> 6.0)
|
- 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):
|
- Folly (2018.10.22.00):
|
||||||
- boost-for-react-native
|
- boost-for-react-native
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
|
@ -73,51 +79,52 @@ PODS:
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- glog
|
- glog
|
||||||
- glog (0.3.5)
|
- glog (0.3.5)
|
||||||
- GoogleAppMeasurement (6.1.1):
|
- GoogleAppMeasurement (6.2.2):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- GoogleUtilities/Network (~> 6.0)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||||
- nanopb (~> 0.3)
|
- nanopb (= 0.3.9011)
|
||||||
- GoogleDataTransport (1.2.0)
|
- GoogleDataTransport (3.3.1)
|
||||||
- GoogleDataTransportCCTSupport (1.0.4):
|
- GoogleDataTransportCCTSupport (1.3.1):
|
||||||
- GoogleDataTransport (~> 1.2)
|
- GoogleDataTransport (~> 3.3)
|
||||||
- nanopb
|
- nanopb (~> 0.3.901)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (6.3.0):
|
- GoogleUtilities/AppDelegateSwizzler (6.5.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network
|
- GoogleUtilities/Network
|
||||||
- GoogleUtilities/Environment (6.3.0)
|
- GoogleUtilities/Environment (6.5.1)
|
||||||
- GoogleUtilities/Logger (6.3.0):
|
- GoogleUtilities/Logger (6.5.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/MethodSwizzler (6.3.0):
|
- GoogleUtilities/MethodSwizzler (6.5.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network (6.3.0):
|
- GoogleUtilities/Network (6.5.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
- GoogleUtilities/Reachability
|
- GoogleUtilities/Reachability
|
||||||
- "GoogleUtilities/NSData+zlib (6.3.0)"
|
- "GoogleUtilities/NSData+zlib (6.5.1)"
|
||||||
- GoogleUtilities/Reachability (6.3.0):
|
- GoogleUtilities/Reachability (6.5.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/UserDefaults (6.3.0):
|
- GoogleUtilities/UserDefaults (6.5.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- JitsiMeetSDK (2.4.0)
|
- JitsiMeetSDK (2.4.0)
|
||||||
- KeyCommands (2.0.3):
|
- KeyCommands (2.0.3):
|
||||||
- React
|
- React
|
||||||
- libwebp (1.0.3):
|
- libwebp (1.1.0):
|
||||||
- libwebp/demux (= 1.0.3)
|
- libwebp/demux (= 1.1.0)
|
||||||
- libwebp/mux (= 1.0.3)
|
- libwebp/mux (= 1.1.0)
|
||||||
- libwebp/webp (= 1.0.3)
|
- libwebp/webp (= 1.1.0)
|
||||||
- libwebp/demux (1.0.3):
|
- libwebp/demux (1.1.0):
|
||||||
- libwebp/webp
|
- libwebp/webp
|
||||||
- libwebp/mux (1.0.3):
|
- libwebp/mux (1.1.0):
|
||||||
- libwebp/demux
|
- libwebp/demux
|
||||||
- libwebp/webp (1.0.3)
|
- libwebp/webp (1.1.0)
|
||||||
- nanopb (0.3.901):
|
- nanopb (0.3.9011):
|
||||||
- nanopb/decode (= 0.3.901)
|
- nanopb/decode (= 0.3.9011)
|
||||||
- nanopb/encode (= 0.3.901)
|
- nanopb/encode (= 0.3.9011)
|
||||||
- nanopb/decode (0.3.901)
|
- nanopb/decode (0.3.9011)
|
||||||
- nanopb/encode (0.3.901)
|
- nanopb/encode (0.3.9011)
|
||||||
|
- PromisesObjC (1.2.8)
|
||||||
- RCTRequired (0.61.5)
|
- RCTRequired (0.61.5)
|
||||||
- RCTTypeSafety (0.61.5):
|
- RCTTypeSafety (0.61.5):
|
||||||
- FBLazyVector (= 0.61.5)
|
- FBLazyVector (= 0.61.5)
|
||||||
|
@ -395,10 +402,10 @@ PODS:
|
||||||
- RNVectorIcons (6.6.0):
|
- RNVectorIcons (6.6.0):
|
||||||
- React
|
- React
|
||||||
- RSKImageCropper (2.2.3)
|
- RSKImageCropper (2.2.3)
|
||||||
- SDWebImage (5.1.1):
|
- SDWebImage (5.5.2):
|
||||||
- SDWebImage/Core (= 5.1.1)
|
- SDWebImage/Core (= 5.5.2)
|
||||||
- SDWebImage/Core (5.1.1)
|
- SDWebImage/Core (5.5.2)
|
||||||
- SDWebImageWebPCoder (0.2.4):
|
- SDWebImageWebPCoder (0.2.5):
|
||||||
- libwebp (~> 1.0)
|
- libwebp (~> 1.0)
|
||||||
- SDWebImage/Core (~> 5.0)
|
- SDWebImage/Core (~> 5.0)
|
||||||
- UMBarCodeScannerInterface (3.0.0)
|
- UMBarCodeScannerInterface (3.0.0)
|
||||||
|
@ -500,7 +507,7 @@ DEPENDENCIES:
|
||||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
https://github.com/CocoaPods/Specs.git:
|
trunk:
|
||||||
- boost-for-react-native
|
- boost-for-react-native
|
||||||
- Crashlytics
|
- Crashlytics
|
||||||
- Fabric
|
- Fabric
|
||||||
|
@ -509,6 +516,7 @@ SPEC REPOS:
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
- FirebaseCoreDiagnostics
|
- FirebaseCoreDiagnostics
|
||||||
- FirebaseCoreDiagnosticsInterop
|
- FirebaseCoreDiagnosticsInterop
|
||||||
|
- FirebaseInstallations
|
||||||
- FirebaseInstanceID
|
- FirebaseInstanceID
|
||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
|
@ -516,6 +524,7 @@ SPEC REPOS:
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
- libwebp
|
- libwebp
|
||||||
- nanopb
|
- nanopb
|
||||||
|
- PromisesObjC
|
||||||
- RSKImageCropper
|
- RSKImageCropper
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
- SDWebImageWebPCoder
|
- SDWebImageWebPCoder
|
||||||
|
@ -713,22 +722,24 @@ SPEC CHECKSUMS:
|
||||||
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
||||||
FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f
|
FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f
|
||||||
FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75
|
FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75
|
||||||
Firebase: 9cbe4e5b5eaafa05dc932be58b7c8c3820d71e88
|
Firebase: 497158b816d0a86fc31babbd05546fcd7e6083ff
|
||||||
FirebaseAnalytics: 843c7f64a8f9c79f0d03281197ebe7bb1d58d477
|
FirebaseAnalytics: cf95d3aab897612783020fbd98401d5366f135ee
|
||||||
FirebaseCore: e9d9bd1dae61c1e82bc1e0e617a9d832392086a0
|
FirebaseCore: 85064903ed6c28e47fec9c7bd149d94ba1b6b6e7
|
||||||
FirebaseCoreDiagnostics: 4c04ae09d0ab027c30179828c6bb47764df1bd13
|
FirebaseCoreDiagnostics: 5e78803ab276bc5b50340e3c539c06c3de35c649
|
||||||
FirebaseCoreDiagnosticsInterop: 6829da2b8d1fc795ff1bd99df751d3788035d2cb
|
FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
|
||||||
FirebaseInstanceID: 550df9be1f99f751d8fcde3ac342a1e21a0e6c42
|
FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b
|
||||||
|
FirebaseInstanceID: 6668efc1655a4052c083f287a7141f1ead12f9c2
|
||||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||||
GoogleAppMeasurement: 86a82f0e1f20b8eedf8e20326530138fd71409de
|
GoogleAppMeasurement: d0560d915abf15e692e8538ba1d58442217b6aff
|
||||||
GoogleDataTransport: 8f9897b8e073687f24ca8d3c3a8013dec7d2d1cc
|
GoogleDataTransport: 0048df6388dab1c254799f2a30365b1dffe20422
|
||||||
GoogleDataTransportCCTSupport: 7455d07b98851aa63e4c05a34dad356ca588479e
|
GoogleDataTransportCCTSupport: f880d70972efa2ed1be4e9173a0f4c5f3dc2d176
|
||||||
GoogleUtilities: 9c2c544202301110b29f7974a82e77fdcf12bf51
|
GoogleUtilities: 06eb53bb579efe7099152735900dd04bf09e7275
|
||||||
JitsiMeetSDK: d4a3aeed1a75fd57e6a78e5d202b6051dfcb9320
|
JitsiMeetSDK: d4a3aeed1a75fd57e6a78e5d202b6051dfcb9320
|
||||||
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
||||||
libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e
|
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
||||||
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
|
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
|
||||||
|
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
|
||||||
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
||||||
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
||||||
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
||||||
|
@ -778,8 +789,8 @@ SPEC CHECKSUMS:
|
||||||
RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6
|
RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6
|
||||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||||
SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8
|
SDWebImage: 4d5c027c935438f341ed33dbac53ff9f479922ca
|
||||||
SDWebImageWebPCoder: cc72085bb20368b2f8dbb21b7e355c667e1309b7
|
SDWebImageWebPCoder: 947093edd1349d820c40afbd9f42acb6cdecd987
|
||||||
UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
|
UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
|
||||||
UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
|
UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
|
||||||
UMConstantsInterface: 038bacb19de12b6fd328c589122c8dc977cccf61
|
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>
|
#import <FirebaseCore/FirebaseCore.h>
|
||||||
|
|
||||||
#if !defined(__has_include)
|
#if !defined(__has_include)
|
||||||
|
@ -12,6 +26,10 @@
|
||||||
#import <FirebaseAuth/FirebaseAuth.h>
|
#import <FirebaseAuth/FirebaseAuth.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<FirebaseCrashlytics/FirebaseCrashlytics.h>)
|
||||||
|
#import <FirebaseCrashlytics/FirebaseCrashlytics.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseDatabase/FirebaseDatabase.h>)
|
#if __has_include(<FirebaseDatabase/FirebaseDatabase.h>)
|
||||||
#import <FirebaseDatabase/FirebaseDatabase.h>
|
#import <FirebaseDatabase/FirebaseDatabase.h>
|
||||||
#endif
|
#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
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
effectively with Firebase services.
|
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.
|
## Installation
|
||||||
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).
|
|
||||||
|
|
||||||
|
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
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
You can try any of the SDKs with `pod try`. Run the following command and select
|
|
||||||
the SDK you are interested in when prompted:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ 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
|
### Carthage (iOS only)
|
||||||
the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/).
|
|
||||||
|
|
||||||
## 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.
|
Instructions for installing binary frameworks via
|
||||||
2. Create a file named `Podfile` in your project directory. This file defines
|
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||||
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:
|
## Development
|
||||||
|
|
||||||
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
|
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 --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).
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
|
||||||
```
|
```
|
||||||
platform :ios, '8.0'
|
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
|
||||||
pod 'Firebase'
|
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Save the file.
|
Note: if you already have a newer version of these installed you may need to
|
||||||
|
`brew switch` to this version.
|
||||||
|
|
||||||
5. Open a terminal and `cd` to the directory containing the Podfile.
|
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:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cd <path-to-project>/project/
|
pod 'Firebase/ABTesting'
|
||||||
```
|
|
||||||
|
|
||||||
6. Run the `pod install` command. This will install the SDKs specified in the
|
|
||||||
Podspec, along with any dependencies they may have.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pod install
|
|
||||||
```
|
|
||||||
|
|
||||||
7. Open your app's `.xcworkspace` file to launch Xcode. Use this file for all
|
|
||||||
development on your app.
|
|
||||||
|
|
||||||
8. You can also install other Firebase SDKs by adding the subspecs in the
|
|
||||||
Podfile.
|
|
||||||
|
|
||||||
```
|
|
||||||
pod 'Firebase/AdMob'
|
|
||||||
pod 'Firebase/Analytics'
|
|
||||||
pod 'Firebase/Auth'
|
pod 'Firebase/Auth'
|
||||||
|
pod 'Firebase/Crashlytics'
|
||||||
pod 'Firebase/Database'
|
pod 'Firebase/Database'
|
||||||
pod 'Firebase/DynamicLinks'
|
|
||||||
pod 'Firebase/Firestore'
|
pod 'Firebase/Firestore'
|
||||||
pod 'Firebase/Functions'
|
pod 'Firebase/Functions'
|
||||||
pod 'Firebase/InAppMessaging'
|
|
||||||
pod 'Firebase/InAppMessagingDisplay'
|
|
||||||
pod 'Firebase/Messaging'
|
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/RemoteConfig'
|
||||||
pod 'Firebase/Storage'
|
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
|
/// 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
|
/// user properties. See <a href="http://goo.gl/gz8SLz">the developer guides</a> for general
|
||||||
/// information on using Firebase Analytics in your apps.
|
/// 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)
|
NS_SWIFT_NAME(Analytics)
|
||||||
@interface FIRAnalytics : NSObject
|
@interface FIRAnalytics : NSObject
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "Private/FIRAnalyticsConfiguration.h"
|
#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h"
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
|
@ -22,17 +22,22 @@
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#import "FIRApp.h"
|
#import <FirebaseCore/FIRApp.h>
|
||||||
|
|
||||||
#import "Private/FIRAnalyticsConfiguration.h"
|
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||||
#import "Private/FIRBundleUtil.h"
|
#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h"
|
||||||
#import "Private/FIRComponentContainerInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "Private/FIRConfigurationInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRComponentContainerInternal.h"
|
||||||
#import "Private/FIRCoreDiagnosticsConnector.h"
|
#import "FirebaseCore/Sources/Private/FIRConfigurationInternal.h"
|
||||||
#import "Private/FIRLibrary.h"
|
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
||||||
#import "Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||||
#import "Private/FIROptionsInternal.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
|
// 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.
|
// 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 NSMutableDictionary *sAllApps;
|
||||||
static FIRApp *sDefaultApp;
|
static FIRApp *sDefaultApp;
|
||||||
static NSMutableDictionary *sLibraryVersions;
|
static NSMutableDictionary *sLibraryVersions;
|
||||||
|
static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
|
|
||||||
+ (void)configure {
|
+ (void)configure {
|
||||||
FIROptions *options = [FIROptions defaultOptions];
|
FIROptions *options = [FIROptions defaultOptions];
|
||||||
|
@ -159,8 +165,9 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
|
|
||||||
if ([name isEqualToString:kFIRDefaultAppName]) {
|
if ([name isEqualToString:kFIRDefaultAppName]) {
|
||||||
if (sDefaultApp) {
|
if (sDefaultApp) {
|
||||||
[NSException raise:kFirebaseCoreErrorDomain
|
// The default app already exixts. Handle duplicate `configure` calls and return.
|
||||||
format:@"Default app has already been configured."];
|
[self appWasConfiguredTwice:sDefaultApp usingOptions:options];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app.");
|
FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app.");
|
||||||
|
@ -176,8 +183,9 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
if (sAllApps && sAllApps[name]) {
|
if (sAllApps && sAllApps[name]) {
|
||||||
[NSException raise:kFirebaseCoreErrorDomain
|
// The app already exists. Handle a duplicate `configure` call and return.
|
||||||
format:@"App named %@ has already been configured.", name];
|
[self appWasConfiguredTwice:sAllApps[name] usingOptions:options];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,10 +199,44 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
[FIRApp addAppToAppDictionary:app];
|
[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];
|
[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 {
|
+ (FIRApp *)defaultApp {
|
||||||
if (sDefaultApp) {
|
if (sDefaultApp) {
|
||||||
return sDefaultApp;
|
return sDefaultApp;
|
||||||
|
@ -236,6 +278,7 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
sAllApps = nil;
|
sAllApps = nil;
|
||||||
[sLibraryVersions removeAllObjects];
|
[sLibraryVersions removeAllObjects];
|
||||||
sLibraryVersions = nil;
|
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.
|
// Check if the Analytics flag is explicitly set. If so, no further actions are necessary.
|
||||||
if ([self.options isAnalyticsCollectionExpicitlySet]) {
|
if ([self.options isAnalyticsCollectionExplicitlySet]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +560,25 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
|
|
||||||
+ (NSString *)firebaseUserAgent {
|
+ (NSString *)firebaseUserAgent {
|
||||||
@synchronized(self) {
|
@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 *> *libraries =
|
||||||
[[NSMutableArray<NSString *> alloc] initWithCapacity:sLibraryVersions.count];
|
[[NSMutableArray<NSString *> alloc] initWithCapacity:sLibraryVersions.count];
|
||||||
for (NSString *libraryName in sLibraryVersions) {
|
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 {
|
- (void)checkExpectedBundleID {
|
||||||
NSArray *bundles = [FIRBundleUtil relevantBundles];
|
NSArray *bundles = [FIRBundleUtil relevantBundles];
|
||||||
NSString *expectedBundleID = [self expectedBundleID];
|
NSString *expectedBundleID = [self expectedBundleID];
|
||||||
|
@ -811,16 +887,16 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
- (void)subscribeForAppDidBecomeActiveNotifications {
|
- (void)subscribeForAppDidBecomeActiveNotifications {
|
||||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification;
|
NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification;
|
||||||
#endif
|
#elif TARGET_OS_OSX
|
||||||
|
|
||||||
#if TARGET_OS_OSX
|
|
||||||
NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification;
|
NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !TARGET_OS_WATCH
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(appDidBecomeActive:)
|
selector:@selector(appDidBecomeActive:)
|
||||||
name:notificationName
|
name:notificationName
|
||||||
object:nil];
|
object:nil];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appDidBecomeActive:(NSNotification *)notification {
|
- (void)appDidBecomeActive:(NSNotification *)notification {
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "Private/FIRAppAssociationRegistration.h"
|
#import "FirebaseCore/Sources/Private/FIRAppAssociationRegistration.h"
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "Private/FIRBundleUtil.h"
|
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||||
|
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Private/FIRComponent.h"
|
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||||
|
|
||||||
#import "Private/FIRComponentContainer.h"
|
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||||
#import "Private/FIRDependency.h"
|
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||||
|
|
||||||
@interface FIRComponent ()
|
@interface FIRComponent ()
|
||||||
|
|
|
@ -14,26 +14,27 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Private/FIRComponentContainer.h"
|
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||||
|
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "Private/FIRComponent.h"
|
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||||
#import "Private/FIRLibrary.h"
|
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||||
#import "Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface FIRComponentContainer () {
|
@interface FIRComponentContainer ()
|
||||||
dispatch_queue_t _containerQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
/// of the protocol.
|
||||||
@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRComponentCreationBlock> *components;
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRComponentCreationBlock> *components;
|
||||||
|
|
||||||
/// Cached instances of components that requested to be cached.
|
/// Cached instances of components that requested to be cached.
|
||||||
@property(nonatomic, strong) NSMutableDictionary<NSString *, id> *cachedInstances;
|
@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
|
@end
|
||||||
|
|
||||||
@implementation FIRComponentContainer
|
@implementation FIRComponentContainer
|
||||||
|
@ -69,8 +70,6 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
_app = app;
|
_app = app;
|
||||||
_cachedInstances = [NSMutableDictionary<NSString *, id> dictionary];
|
_cachedInstances = [NSMutableDictionary<NSString *, id> dictionary];
|
||||||
_components = [NSMutableDictionary<NSString *, FIRComponentCreationBlock> dictionary];
|
_components = [NSMutableDictionary<NSString *, FIRComponentCreationBlock> dictionary];
|
||||||
_containerQueue =
|
|
||||||
dispatch_queue_create("com.google.FirebaseComponentContainer", DISPATCH_QUEUE_SERIAL);
|
|
||||||
|
|
||||||
[self populateComponentsFromRegisteredClasses:allRegistrants forApp:app];
|
[self populateComponentsFromRegisteredClasses:allRegistrants forApp:app];
|
||||||
}
|
}
|
||||||
|
@ -78,6 +77,9 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)populateComponentsFromRegisteredClasses:(NSSet<Class> *)classes forApp:(FIRApp *)app {
|
- (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.
|
// Loop through the verified component registrants and populate the components array.
|
||||||
for (Class<FIRLibrary> klass in classes) {
|
for (Class<FIRLibrary> klass in classes) {
|
||||||
// Loop through all the components being registered and store them as appropriate.
|
// 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.
|
// Store the creation block for later usage.
|
||||||
self.components[protocolName] = component.creationBlock;
|
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 =
|
BOOL shouldInstantiateEager =
|
||||||
(component.instantiationTiming == FIRInstantiationTimingAlwaysEager);
|
(component.instantiationTiming == FIRInstantiationTimingAlwaysEager);
|
||||||
BOOL shouldInstantiateDefaultEager =
|
BOOL shouldInstantiateDefaultEager =
|
||||||
(component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp &&
|
(component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp &&
|
||||||
[app isDefaultApp]);
|
[app isDefaultApp]);
|
||||||
if (shouldInstantiateEager || shouldInstantiateDefaultEager) {
|
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
|
#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.
|
/// Instantiate an instance of a class that conforms to the specified protocol.
|
||||||
/// This will:
|
/// This will:
|
||||||
/// - Call the block to create an instance if possible,
|
/// - Call the block to create an instance if possible,
|
||||||
/// - Validate that the instance returned conforms to the protocol it claims to,
|
/// - Validate that the instance returned conforms to the protocol it claims to,
|
||||||
/// - Cache the instance if the block requests it
|
/// - 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
|
- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol
|
||||||
withBlock:(FIRComponentCreationBlock)creationBlock {
|
withBlock:(FIRComponentCreationBlock)creationBlock {
|
||||||
if (!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.
|
// The instance is ready to be returned, but check if it should be cached first before returning.
|
||||||
if (shouldCache) {
|
if (shouldCache) {
|
||||||
dispatch_sync(_containerQueue, ^{
|
|
||||||
self.cachedInstances[protocolName] = instance;
|
self.cachedInstances[protocolName] = instance;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
|
@ -153,47 +172,35 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
- (nullable id)instanceForProtocol:(Protocol *)protocol {
|
- (nullable id)instanceForProtocol:(Protocol *)protocol {
|
||||||
// Check if there is a cached instance, and return it if so.
|
// Check if there is a cached instance, and return it if so.
|
||||||
NSString *protocolName = NSStringFromProtocol(protocol);
|
NSString *protocolName = NSStringFromProtocol(protocol);
|
||||||
__block id cachedInstance;
|
|
||||||
dispatch_sync(_containerQueue, ^{
|
id cachedInstance;
|
||||||
|
@synchronized(self) {
|
||||||
cachedInstance = self.cachedInstances[protocolName];
|
cachedInstance = self.cachedInstances[protocolName];
|
||||||
});
|
if (!cachedInstance) {
|
||||||
|
|
||||||
if (cachedInstance) {
|
|
||||||
return cachedInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the creation block to instantiate an instance and return it.
|
// Use the creation block to instantiate an instance and return it.
|
||||||
FIRComponentCreationBlock creationBlock = self.components[protocolName];
|
FIRComponentCreationBlock creationBlock = self.components[protocolName];
|
||||||
return [self instantiateInstanceForProtocol:protocol withBlock:creationBlock];
|
cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cachedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Lifecycle
|
#pragma mark - Lifecycle
|
||||||
|
|
||||||
- (void)removeAllCachedInstances {
|
- (void)removeAllCachedInstances {
|
||||||
// Loop through the cache and notify each instance that is a maintainer to clean up after itself.
|
@synchronized(self) {
|
||||||
// Design note: we're getting a copy here, unlocking the cached instances, iterating over the
|
// Loop through the cache and notify each instance that is a maintainer to clean up after
|
||||||
// copy, then locking and removing all cached instances. A race condition *could* exist where a
|
// itself.
|
||||||
// new cached instance is created between the copy and the removal, but the chances are slim and
|
for (id instance in self.cachedInstances.allValues) {
|
||||||
// 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)] &&
|
if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] &&
|
||||||
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
||||||
[instance appWillBeDeleted:self.app];
|
[instance appWillBeDeleted:self.app];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instancesCopy = nil;
|
|
||||||
|
|
||||||
// Empty the cache.
|
// Empty the cache.
|
||||||
dispatch_sync(_containerQueue, ^{
|
|
||||||
[self.cachedInstances removeAllObjects];
|
[self.cachedInstances removeAllObjects];
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
|
@ -14,9 +14,9 @@
|
||||||
* limitations under the License.
|
* 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
|
@implementation FIRComponentType
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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);
|
extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
|
||||||
|
|
|
@ -14,15 +14,15 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Private/FIRCoreDiagnosticsConnector.h"
|
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
||||||
|
|
||||||
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsInterop.h>
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsInterop.h>
|
||||||
|
|
||||||
#import <FirebaseCore/FIROptions.h>
|
#import <FirebaseCore/FIROptions.h>
|
||||||
|
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "Private/FIRDiagnosticsData.h"
|
#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h"
|
||||||
#import "Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
|
|
||||||
// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop.
|
// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop.
|
||||||
Class<FIRCoreDiagnosticsInterop> FIRCoreDiagnosticsImplementation;
|
Class<FIRCoreDiagnosticsInterop> FIRCoreDiagnosticsImplementation;
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Private/FIRDependency.h"
|
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||||
|
|
||||||
@interface FIRDependency ()
|
@interface FIRDependency ()
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "Private/FIRDiagnosticsData.h"
|
#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h"
|
||||||
|
|
||||||
#import <FirebaseCore/FIRApp.h>
|
#import <FirebaseCore/FIRApp.h>
|
||||||
|
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
|
|
||||||
@implementation FIRDiagnosticsData {
|
@implementation FIRDiagnosticsData {
|
||||||
/** Backing ivar for the diagnosticObjects property. */
|
/** Backing ivar for the diagnosticObjects property. */
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "Private/FIRErrors.h"
|
#import "FirebaseCore/Sources/Private/FIRErrors.h"
|
||||||
|
|
||||||
NSString *const kFirebaseErrorDomain = @"com.firebase";
|
NSString *const kFirebaseErrorDomain = @"com.firebase";
|
||||||
NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config";
|
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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||||
|
|
||||||
#import <FirebaseCore/FIRLoggerLevel.h>
|
#import <FirebaseCore/FIRLoggerLevel.h>
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
#import <GoogleUtilities/GULLogger.h>
|
#import <GoogleUtilities/GULLogger.h>
|
||||||
|
|
||||||
#import "Private/FIRVersion.h"
|
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||||
|
|
||||||
FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]";
|
FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]";
|
||||||
|
|
|
@ -12,12 +12,11 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||||
#import "Private/FIRBundleUtil.h"
|
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||||
#import "Private/FIRErrors.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||||
#import "Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
#import "Private/FIRVersion.h"
|
|
||||||
|
|
||||||
// Keys for the strings in the plist file.
|
// Keys for the strings in the plist file.
|
||||||
NSString *const kFIRAPIKey = @"API_KEY";
|
NSString *const kFIRAPIKey = @"API_KEY";
|
||||||
|
@ -110,22 +109,6 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
|
|
||||||
#pragma mark - Private class methods
|
#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 {
|
+ (NSDictionary *)defaultOptionsDictionary {
|
||||||
if (sDefaultOptionsDictionary != nil) {
|
if (sDefaultOptionsDictionary != nil) {
|
||||||
return sDefaultOptionsDictionary;
|
return sDefaultOptionsDictionary;
|
||||||
|
@ -346,6 +329,59 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
_appGroupID = [appGroupID copy];
|
_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
|
#pragma mark - Internal instance methods
|
||||||
|
|
||||||
- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary {
|
- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary {
|
||||||
|
@ -399,7 +435,7 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
return [value boolValue];
|
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
|
// 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.
|
// that the developer wants FirebaseAnalytics enabled so continue checking.
|
||||||
if (self.isAnalyticsCollectionDeactivated) {
|
if (self.isAnalyticsCollectionDeactivated) {
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FIRComponentType.h"
|
#import <FirebaseCore/FIRComponentType.h>
|
||||||
#import "FIRLibrary.h"
|
#import <FirebaseCore/FIRLibrary.h>
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FIRComponent.h"
|
#import <FirebaseCore/FIRComponent.h>
|
||||||
#import "FIRComponentContainer.h"
|
#import <FirebaseCore/FIRComponentContainer.h>
|
||||||
|
|
||||||
@class FIRApp;
|
@class FIRApp;
|
||||||
|
|
||||||
|
@ -24,13 +24,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface FIRComponentContainer (Private)
|
@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;
|
- (instancetype)initWithApp:(FIRApp *)app;
|
||||||
|
|
||||||
/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the
|
/// 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:));
|
- (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.
|
/// Remove all of the cached instances stored and allow them to clean up after themselves.
|
||||||
- (void)removeAllCachedInstances;
|
- (void)removeAllCachedInstances;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "FIRConfiguration.h"
|
#import <FirebaseCore/FIRConfiguration.h>
|
||||||
|
|
||||||
@class FIRAnalyticsConfiguration;
|
@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
|
#define FIRLibrary_h
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "FIRComponent.h"
|
|
||||||
|
#import <FirebaseCore/FIRComponent.h>
|
||||||
|
|
||||||
@class FIRApp;
|
@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
|
* Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at
|
||||||
* runtime.
|
* runtime.
|
||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly) BOOL isAnalyticsCollectionExpicitlySet;
|
@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless
|
* 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
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||||
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||||
|
FirebaseStorage.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
The repository also includes GoogleUtilities source. The
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||||
|
@ -75,14 +76,31 @@ the following software:
|
||||||
|
|
||||||
* Xcode 10.1 (or later)
|
* Xcode 10.1 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
* CocoaPods 1.7.2 (or later)
|
||||||
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
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 has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md).
|
[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
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
See [AddNewPod.md](AddNewPod.md).
|
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:
|
These commands will get the right versions:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/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/7963c3d/Formula/swiftformat.rb
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
Note: if you already have a newer version of these installed you may need to
|
||||||
`brew switch` to this version.
|
`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
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its 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
|
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.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### macOS and tvOS
|
### tvOS, macOS, and Catalyst
|
||||||
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||||
FirebaseDatabase, FirebaseMessaging,
|
tvOS, macOS, and Catalyst.
|
||||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
|
||||||
macOS and tvOS.
|
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
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:
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
```
|
```
|
||||||
pod 'FirebaseABTesting'
|
pod 'Firebase/ABTesting'
|
||||||
pod 'FirebaseAuth'
|
pod 'Firebase/Auth'
|
||||||
pod 'FirebaseCore'
|
pod 'Firebase/Crashlytics'
|
||||||
pod 'FirebaseDatabase'
|
pod 'Firebase/Database'
|
||||||
pod 'FirebaseFirestore'
|
pod 'Firebase/Firestore'
|
||||||
pod 'FirebaseFunctions'
|
pod 'Firebase/Functions'
|
||||||
pod 'FirebaseMessaging'
|
pod 'Firebase/Messaging'
|
||||||
pod 'FirebaseStorage'
|
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
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
|
||||||
#import <GoogleDataTransport/GDTEvent.h>
|
#import <GoogleDataTransport/GDTCOREvent.h>
|
||||||
#import <GoogleDataTransport/GDTTargets.h>
|
#import <GoogleDataTransport/GDTCORTargets.h>
|
||||||
#import <GoogleDataTransport/GDTTransport.h>
|
#import <GoogleDataTransport/GDTCORTransport.h>
|
||||||
|
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||||
#import <GoogleUtilities/GULLogger.h>
|
#import <GoogleUtilities/GULLogger.h>
|
||||||
|
|
||||||
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsData.h>
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsData.h>
|
||||||
|
@ -34,8 +35,6 @@
|
||||||
|
|
||||||
#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
||||||
|
|
||||||
#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h"
|
|
||||||
|
|
||||||
/** The logger service string to use when printing to the console. */
|
/** The logger service string to use when printing to the console. */
|
||||||
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
||||||
|
|
||||||
|
@ -85,6 +84,7 @@ static NSString *const kFIRAppDiagnosticsConfigurationTypeKey =
|
||||||
static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey";
|
static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey";
|
||||||
static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey";
|
static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey";
|
||||||
static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey";
|
static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey";
|
||||||
|
static NSString *const kFIRCoreDiagnosticsHeartbeatTag = @"FIRCoreDiagnostics";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The file name to the recent heartbeat date.
|
* The file name to the recent heartbeat date.
|
||||||
|
@ -92,7 +92,8 @@ static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKV
|
||||||
NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE";
|
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
|
@interface FIRCoreDiagnosticsLog : NSObject
|
||||||
|
|
||||||
|
@ -111,13 +112,13 @@ NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTIC
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provided and required by the GDTEventDataObject protocol.
|
// Provided and required by the GDTCOREventDataObject protocol.
|
||||||
- (NSData *)transportBytes {
|
- (NSData *)transportBytes {
|
||||||
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
||||||
|
|
||||||
// Encode 1 time to determine the size.
|
// Encode 1 time to determine the size.
|
||||||
if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||||
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for size: %s",
|
GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s",
|
||||||
PB_GET_ERROR(&sizestream));
|
PB_GET_ERROR(&sizestream));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTIC
|
||||||
CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
|
CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
|
||||||
pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
|
pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
|
||||||
if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||||
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
|
GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
|
||||||
PB_GET_ERROR(&ostream));
|
PB_GET_ERROR(&ostream));
|
||||||
}
|
}
|
||||||
CFDataSetLength(dataRef, ostream.bytes_written);
|
CFDataSetLength(dataRef, ostream.bytes_written);
|
||||||
|
@ -149,10 +150,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue;
|
@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue;
|
||||||
|
|
||||||
/** The transport object used to send data. */
|
/** 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. */
|
/** The storage to store the date of the last sent heartbeat. */
|
||||||
@property(nonatomic, readonly) FIRCoreDiagnosticsDateFileStorage *heartbeatDateStorage;
|
@property(nonatomic, readonly) GULHeartbeatDateStorage *heartbeatDateStorage;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -170,24 +171,24 @@ NS_ASSUME_NONNULL_END
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
GDTTransport *transport = [[GDTTransport alloc] initWithMappingID:@"137"
|
GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"137"
|
||||||
transformers:nil
|
transformers:nil
|
||||||
target:kGDTTargetCCT];
|
target:kGDTCORTargetFLL];
|
||||||
|
|
||||||
FIRCoreDiagnosticsDateFileStorage *dateStorage = [[FIRCoreDiagnosticsDateFileStorage alloc]
|
GULHeartbeatDateStorage *dateStorage =
|
||||||
initWithFileURL:[[self class] filePathURLWithName:kFIRCoreDiagnosticsHeartbeatDateFileName]];
|
[[GULHeartbeatDateStorage alloc] initWithFileName:kFIRCoreDiagnosticsHeartbeatDateFileName];
|
||||||
|
|
||||||
return [self initWithTransport:transport heartbeatDateStorage:dateStorage];
|
return [self initWithTransport:transport heartbeatDateStorage:dateStorage];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initializer for unit tests.
|
/** 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.
|
* @param heartbeatDateStorage An instanse of date storage to track heartbeat sending.
|
||||||
* @return Returns the initialized `FIRCoreDiagnostics` instance.
|
* @return Returns the initialized `FIRCoreDiagnostics` instance.
|
||||||
*/
|
*/
|
||||||
- (instancetype)initWithTransport:(GDTTransport *)transport
|
- (instancetype)initWithTransport:(GDTCORTransport *)transport
|
||||||
heartbeatDateStorage:(FIRCoreDiagnosticsDateFileStorage *)heartbeatDateStorage {
|
heartbeatDateStorage:(GULHeartbeatDateStorage *)heartbeatDateStorage {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_diagnosticsQueue =
|
_diagnosticsQueue =
|
||||||
|
@ -198,37 +199,6 @@ NS_ASSUME_NONNULL_END
|
||||||
return self;
|
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
|
#pragma mark - Metadata helpers
|
||||||
|
|
||||||
/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus,
|
/** 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;
|
config->has_pod_name = 1;
|
||||||
|
|
||||||
if (!diagnosticObjects[kFIRCDllAppsCountKey]) {
|
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->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue];
|
||||||
config->has_app_count = 1;
|
config->has_app_count = 1;
|
||||||
|
@ -635,8 +606,8 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
||||||
FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config];
|
FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config];
|
||||||
|
|
||||||
// Send the log as a telemetry event.
|
// Send the log as a telemetry event.
|
||||||
GDTEvent *event = [self.transport eventForTransport];
|
GDTCOREvent *event = [self.transport eventForTransport];
|
||||||
event.dataObject = (id<GDTEventDataObject>)log;
|
event.dataObject = (id<GDTCOREventDataObject>)log;
|
||||||
[self.transport sendTelemetryEvent:event];
|
[self.transport sendTelemetryEvent:event];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -646,7 +617,8 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
||||||
- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config {
|
- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config {
|
||||||
// Check if need to send a heartbeat.
|
// Check if need to send a heartbeat.
|
||||||
NSDate *currentDate = [NSDate date];
|
NSDate *currentDate = [NSDate date];
|
||||||
NSDate *lastCheckin = [self.heartbeatDateStorage date];
|
NSDate *lastCheckin =
|
||||||
|
[self.heartbeatDateStorage heartbeatDateForTag:kFIRCoreDiagnosticsHeartbeatTag];
|
||||||
if (lastCheckin) {
|
if (lastCheckin) {
|
||||||
// Ensure the previous checkin was on a different date in the past.
|
// Ensure the previous checkin was on a different date in the past.
|
||||||
if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) {
|
if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) {
|
||||||
|
@ -655,12 +627,7 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update heartbeat sent date.
|
// Update heartbeat sent date.
|
||||||
NSError *error;
|
[self.heartbeatDateStorage setHearbeatDate:currentDate forTag:kFIRCoreDiagnosticsHeartbeatTag];
|
||||||
if (![self.heartbeatDateStorage setDate:currentDate error:&error]) {
|
|
||||||
GULLogError(kFIRCoreDiagnostics, NO, @"I-COR100004", @"Unable to persist internal state: %@",
|
|
||||||
error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the flag.
|
// Set the flag.
|
||||||
config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE;
|
config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE;
|
||||||
config->has_sdk_name = 1;
|
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 */
|
/* Automatically generated nanopb constant definitions */
|
||||||
/* Generated by nanopb-0.3.9.2 */
|
/* Generated by nanopb-0.3.9.3 */
|
||||||
|
|
||||||
#include "firebasecore.nanopb.h"
|
#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( 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( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, 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( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 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( 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, app_id, 0),
|
||||||
PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, project_number, 0),
|
PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, bundle_id, 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( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 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( 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( 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( 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( 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, os_version, 0),
|
||||||
PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, itunes_id, 0),
|
|
||||||
PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_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( 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),
|
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( 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( 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( 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, platform_info, 0),
|
||||||
PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, app_extensions, 0),
|
PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, swizzling_enabled, 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_LAST_FIELD
|
PB_LAST_FIELD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Automatically generated nanopb header */
|
/* 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
|
#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||||
#define 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 {
|
typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
||||||
bool has_configuration_type;
|
bool has_configuration_type;
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType 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;
|
pb_size_t sdk_service_installed_count;
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed;
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed;
|
||||||
pb_bytes_array_t *device_model;
|
pb_bytes_array_t *device_model;
|
||||||
pb_bytes_array_t *app_id;
|
pb_bytes_array_t *app_id;
|
||||||
bool has_project_number;
|
|
||||||
int64_t project_number;
|
|
||||||
pb_bytes_array_t *bundle_id;
|
pb_bytes_array_t *bundle_id;
|
||||||
pb_bytes_array_t *client_id;
|
|
||||||
pb_bytes_array_t *install;
|
|
||||||
bool has_pod_name;
|
bool has_pod_name;
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name;
|
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name;
|
||||||
pb_bytes_array_t *icore_version;
|
pb_bytes_array_t *icore_version;
|
||||||
|
@ -137,7 +125,6 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
||||||
bool has_app_count;
|
bool has_app_count;
|
||||||
int32_t app_count;
|
int32_t app_count;
|
||||||
pb_bytes_array_t *os_version;
|
pb_bytes_array_t *os_version;
|
||||||
pb_bytes_array_t *itunes_id;
|
|
||||||
pb_bytes_array_t *min_supported_ios_version;
|
pb_bytes_array_t *min_supported_ios_version;
|
||||||
bool has_use_default_app;
|
bool has_use_default_app;
|
||||||
bool use_default_app;
|
bool use_default_app;
|
||||||
|
@ -151,14 +138,8 @@ typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
||||||
bool has_deployment_type;
|
bool has_deployment_type;
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type;
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type;
|
||||||
pb_bytes_array_t *platform_info;
|
pb_bytes_array_t *platform_info;
|
||||||
bool has_app_extensions;
|
|
||||||
int64_t app_extensions;
|
|
||||||
bool has_swizzling_enabled;
|
bool has_swizzling_enabled;
|
||||||
bool 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 has_using_gdt;
|
||||||
bool using_gdt;
|
bool using_gdt;
|
||||||
/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */
|
/* @@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 */
|
/* Default values for struct fields */
|
||||||
|
|
||||||
/* Initializer values for message structs */
|
/* 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_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, 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, 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) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16
|
#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_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_icore_version_tag 18
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19
|
#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_service_installed_tag 7
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20
|
#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_device_model_tag 9
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22
|
#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_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_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_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_use_default_app_tag 25
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26
|
#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_using_zip_file_tag 29
|
||||||
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30
|
#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_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_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
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* 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) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */
|
/* 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)
|
# 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
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||||
|
FirebaseStorage.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
The repository also includes GoogleUtilities source. The
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||||
|
@ -75,14 +76,30 @@ the following software:
|
||||||
|
|
||||||
* Xcode 10.1 (or later)
|
* Xcode 10.1 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
* CocoaPods 1.7.2 (or later)
|
||||||
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
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
|
Note: If the CocoaPods cache is out of date, you may need to run
|
||||||
[Firestore/README.md](Firestore/README.md) and
|
`pod repo update` before the `pod gen` command.
|
||||||
[Functions/README.md](Functions/README.md).
|
|
||||||
|
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
|
### 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:
|
These commands will get the right versions:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/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/7963c3d/Formula/swiftformat.rb
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
Note: if you already have a newer version of these installed you may need to
|
||||||
`brew switch` to this version.
|
`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
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its 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
|
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.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### macOS and tvOS
|
### tvOS, macOS, and Catalyst
|
||||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
FirebaseDatabase, FirebaseMessaging, FirebaseFirestore,
|
||||||
macOS and tvOS.
|
FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on
|
||||||
|
tvOS, macOS, and Catalyst.
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
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.
|
|
||||||
|
|
||||||
To install, add a subset of the following to the Podfile:
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
```
|
```
|
||||||
pod 'FirebaseAuth'
|
pod 'Firebase/ABTesting'
|
||||||
pod 'FirebaseCore'
|
pod 'Firebase/Auth'
|
||||||
pod 'FirebaseDatabase'
|
pod 'Firebase/Database'
|
||||||
pod 'FirebaseFirestore'
|
pod 'Firebase/Firestore'
|
||||||
pod 'FirebaseFunctions'
|
pod 'Firebase/Functions'
|
||||||
pod 'FirebaseMessaging'
|
pod 'Firebase/Messaging'
|
||||||
pod 'FirebaseStorage'
|
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
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
|
|
@ -19,36 +19,34 @@
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/** If present, is a BOOL wrapped in an NSNumber. */
|
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||||
static NSString *const kFIRCDIsDataCollectionDefaultEnabledKey =
|
#define kFIRCDIsDataCollectionDefaultEnabledKey @"FIRCDIsDataCollectionDefaultEnabledKey"
|
||||||
@"FIRCDIsDataCollectionDefaultEnabledKey";
|
|
||||||
|
|
||||||
/** If present, is an int32_t wrapped in an NSNumber. */
|
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||||
static NSString *const kFIRCDConfigurationTypeKey = @"FIRCDConfigurationTypeKey";
|
#define kFIRCDConfigurationTypeKey @"FIRCDConfigurationTypeKey"
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** If present, is an NSString. */
|
||||||
static NSString *const kFIRCDSdkNameKey = @"FIRCDSdkNameKey";
|
#define kFIRCDSdkNameKey @"FIRCDSdkNameKey"
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** If present, is an NSString. */
|
||||||
static NSString *const kFIRCDSdkVersionKey = @"FIRCDSdkVersionKey";
|
#define kFIRCDSdkVersionKey @"FIRCDSdkVersionKey"
|
||||||
|
|
||||||
/** If present, is an int32_t wrapped in an NSNumber. */
|
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||||
static NSString *const kFIRCDllAppsCountKey = @"FIRCDllAppsCountKey";
|
#define kFIRCDllAppsCountKey @"FIRCDllAppsCountKey"
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** If present, is an NSString. */
|
||||||
static NSString *const kFIRCDGoogleAppIDKey = @"FIRCDGoogleAppIDKey";
|
#define kFIRCDGoogleAppIDKey @"FIRCDGoogleAppIDKey"
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** If present, is an NSString. */
|
||||||
static NSString *const kFIRCDBundleIDKey = @"FIRCDBundleID";
|
#define kFIRCDBundleIDKey @"FIRCDBundleID"
|
||||||
|
|
||||||
/** If present, is a BOOL wrapped in an NSNumber. */
|
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||||
static NSString *const kFIRCDUsingOptionsFromDefaultPlistKey =
|
#define kFIRCDUsingOptionsFromDefaultPlistKey @"FIRCDUsingOptionsFromDefaultPlistKey"
|
||||||
@"FIRCDUsingOptionsFromDefaultPlistKey";
|
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** If present, is an NSString. */
|
||||||
static NSString *const kFIRCDLibraryVersionIDKey = @"FIRCDLibraryVersionIDKey";
|
#define kFIRCDLibraryVersionIDKey @"FIRCDLibraryVersionIDKey"
|
||||||
|
|
||||||
/** If present, is an NSString. */
|
/** 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. */
|
/** Defines the interface of a data object needed to log diagnostics data. */
|
||||||
@protocol FIRCoreDiagnosticsData <NSObject>
|
@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)
|
# 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
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
|
||||||
|
FirebaseStorage.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
The repository also includes GoogleUtilities source. The
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||||
|
@ -75,14 +76,30 @@ the following software:
|
||||||
|
|
||||||
* Xcode 10.1 (or later)
|
* Xcode 10.1 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
* CocoaPods 1.7.2 (or later)
|
||||||
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
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
|
Note: If the CocoaPods cache is out of date, you may need to run
|
||||||
[Firestore/README.md](Firestore/README.md) and
|
`pod repo update` before the `pod gen` command.
|
||||||
[Functions/README.md](Functions/README.md).
|
|
||||||
|
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
|
### 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:
|
These commands will get the right versions:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/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/7963c3d/Formula/swiftformat.rb
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
Note: if you already have a newer version of these installed you may need to
|
||||||
`brew switch` to this version.
|
`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
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its 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
|
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.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### macOS and tvOS
|
### tvOS, macOS, and Catalyst
|
||||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
FirebaseDatabase, FirebaseMessaging, FirebaseFirestore,
|
||||||
macOS and tvOS.
|
FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on
|
||||||
|
tvOS, macOS, and Catalyst.
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this
|
||||||
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||||
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you
|
||||||
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
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.
|
|
||||||
|
|
||||||
To install, add a subset of the following to the Podfile:
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
```
|
```
|
||||||
pod 'FirebaseAuth'
|
pod 'Firebase/ABTesting'
|
||||||
pod 'FirebaseCore'
|
pod 'Firebase/Auth'
|
||||||
pod 'FirebaseDatabase'
|
pod 'Firebase/Database'
|
||||||
pod 'FirebaseFirestore'
|
pod 'Firebase/Firestore'
|
||||||
pod 'FirebaseFunctions'
|
pod 'Firebase/Functions'
|
||||||
pod 'FirebaseMessaging'
|
pod 'Firebase/Messaging'
|
||||||
pod 'FirebaseStorage'
|
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
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
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